若依vue -【 44】

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

44 服务监控讲解

1 需求

        显示CPU、内存、服务器信息、Java虚拟机信息、磁盘状态的信息

2 前端

  1. RuoYi-Vue\ruoyi-ui\src\views\monitor\server\index.vue
    <script>
    import { getServer } from "@/api/monitor/server";
    
    export default {
      name: "Server",
      data() {
        return {
          // 服务器信息
          server: []
        };
      },
      created() {
        this.getList();
        this.openLoading();
      },
      methods: {
        /** 查询服务器信息 */
        getList() {
          getServer().then(response => {
            this.server = response.data;
            this.$modal.closeLoading();
          });
        },
        // 打开加载层
        openLoading() {
          this.$modal.loading("正在加载服务监控数据请稍候");
        }
      }
    };
    </script>
  2. RuoYi-Vue\ruoyi-ui\src\api\monitor\server.js
    import request from '@/utils/request'
    
    // 获取服务信息
    export function getServer() {
      return request({
        url: '/monitor/server',
        method: 'get'
      })
    }

3 后端

  1. RuoYi-Vue\pom.xml引入开源框架获取cpu、内存、磁盘等信息。
    <!-- 获取系统信息 -->
    <dependency>
        <groupId>com.github.oshi</groupId>
        <artifactId>oshi-core</artifactId>
        <version>${oshi.version}</version>
    </dependency>
  2. RuoYi-Vue\ruoyi-framework\pom.xml引入开源框架获取cpu、内存、磁盘等信息。
    <!-- 获取系统信息 -->
    <dependency>
        <groupId>com.github.oshi</groupId>
        <artifactId>oshi-core</artifactId>
    </dependency>
  3. ServerController#getInfo
    /**
     * 服务器监控
     * 
     * @author ruoyi
     */
    @RestController
    @RequestMapping("/monitor/server")
    public class ServerController
    {
        @PreAuthorize("@ss.hasPermi('monitor:server:list')")
        @GetMapping()
        public AjaxResult getInfo() throws Exception
        {
            // 实例化
            Server server = new Server();
            // 设置相关的值
            server.copyTo();
            // 返回给前端
            return AjaxResult.success(server);
        }
    }
  4. Server返回数据
    /**
     * 服务器相关信息
     * 
     * @author ruoyi
     */
    public class Server
    {
        private static final int OSHI_WAIT_SECOND = 1000;
        
        /**
         * CPU相关信息
         */
        private Cpu cpu = new Cpu();
    
        /**
         * 內存相关信息
         */
        private Mem mem = new Mem();
    
        /**
         * JVM相关信息
         */
        private Jvm jvm = new Jvm();
    
        /**
         * 服务器相关信息
         */
        private Sys sys = new Sys();
    
        /**
         * 磁盘相关信息
         */
        private List<SysFile> sysFiles = new LinkedList<SysFile>();
    }
  5. Server#copyTo数据填充
        /**
         * 数据填充
         */
        public void copyTo() throws Exception
        {
            // SystemInfo框架api
            SystemInfo si = new SystemInfo();
            // SystemInfo框架api
            HardwareAbstractionLayer hal = si.getHardware();
            // cpu信息大多从开源框架的API中获取
            setCpuInfo(hal.getProcessor());
            // 内存信息
            setMemInfo(hal.getMemory());
            // 服务器信息
            setSysInfo();
            // 虚拟机信息jdk的API
            setJvmInfo();
            // 磁盘信息
            setSysFiles(si.getOperatingSystem());
        }
  6. Cpu.java
    /**
     * CPU相关信息
     * 
     * @author ruoyi
     */
    public class Cpu
    {
        /**
         * 核心数
         */
        private int cpuNum;
    
        /**
         * CPU总的使用率
         */
        private double total;
    
        /**
         * CPU系统使用率
         */
        private double sys;
    
        /**
         * CPU用户使用率
         */
        private double used;
    
        /**
         * CPU当前等待率
         */
        private double wait;
    
        /**
         * CPU当前空闲率
         */
        private double free;
    }
  7. Jvm.java
    /**
     * JVM相关信息
     * 
     * @author ruoyi
     */
    public class Jvm
    {
        /**
         * 当前JVM占用的内存总数(M)
         */
        private double total;
    
        /**
         * JVM最大可用内存总数(M)
         */
        private double max;
    
        /**
         * JVM空闲内存(M)
         */
        private double free;
    
        /**
         * JDK版本
         */
        private String version;
    
        /**
         * JDK路径
         */
        private String home;
    }
  8. Mem.java
    /**
     * 內存相关信息
     * 
     * @author ruoyi
     */
    public class Mem
    {
        /**
         * 内存总量
         */
        private double total;
    
        /**
         * 已用内存
         */
        private double used;
    
        /**
         * 剩余内存
         */
        private double free;
    }
  9. Sys.java
    /**
     * 系统相关信息
     * 
     * @author ruoyi
     */
    public class Sys
    {
        /**
         * 服务器名称
         */
        private String computerName;
    
        /**
         * 服务器Ip
         */
        private String computerIp;
    
        /**
         * 项目路径
         */
        private String userDir;
    
        /**
         * 操作系统
         */
        private String osName;
    
        /**
         * 系统架构
         */
        private String osArch;
    }
  10. SysFile.java
    /**
     * 系统文件相关信息
     * 
     * @author ruoyi
     */
    public class SysFile
    {
        /**
         * 盘符路径
         */
        private String dirName;
    
        /**
         * 盘符类型
         */
        private String sysTypeName;
    
        /**
         * 文件类型
         */
        private String typeName;
    
        /**
         * 总大小
         */
        private String total;
    
        /**
         * 剩余大小
         */
        private String free;
    
        /**
         * 已经使用量
         */
        private String used;
    
        /**
         * 资源的使用率
         */
        private double usage;
    }

    4 拓展

4 拓展集群

        如果要做成集群就需要再扩展一下

  1. 需要一个表去控制把服务器的的名称、IP、地址等相关信息入库。
  2. 然后需要做实时的监控比如使用websocket。

45 系统接口使用详解 

1 需求

        api文档

2 效果

3 使用

  1. 第一步获取token
  2. 第二步点击" Authorize "配置token
  3. 第三步传参数调接口

4 拓展

  1. 可以使用很多第三方插件把界面优化的更漂亮。

46 系统接口实现详解

1 RuoYi-Vue\pom.xml

    <properties>
        <swagger.version>3.0.0</swagger.version>
    </properties>

            <!-- Swagger3依赖 -->
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-boot-starter</artifactId>
                <version>${swagger.version}</version>
                <exclusions>
                    <!--
                        排除它和前端的UI有冲突
                    -->
                    <exclusion>
                        <groupId>io.swagger</groupId>
                        <artifactId>swagger-models</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>

2 RuoYi-Vue\ruoyi-admin\pom.xml

        <!-- swagger3
             界面是swagger ui渲染出来的。
             而sawagger ui的所有页面都在它的jar包中。
        -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-boot-starter</artifactId>
        </dependency>

        <!-- 
             因为与前端ui冲突所以做了排除。
             并把版本降了一下。
        -->
        <!-- 防止进入swagger页面报类型转换错误排除3.0.0中的引用手动增加1.6.2版本 -->
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
            <version>1.6.2</version>
        </dependency>

3 前端

  1. ruoyi-ui\src\views\tool\swagger\index.vue
    <template>
      <!--url指定了后台的接口地址 -->
      <i-frame :src="url" />
    </template>
    <script>
    import iFrame from "@/components/iFrame/index";
    export default {
      name: "Swagger",
      components: { iFrame },
      data() {
        return {
          url: process.env.VUE_APP_BASE_API + "/swagger-ui/index.html"
        };
      },
    };
    </script>

4 后端

  1. ResourcesConfig#addResourceHandlersswagger ui映射。swagger ui怎么去加载的呢
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry)
        {
            /** 本地文件上传路径 */
            registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**")
                    .addResourceLocations("file:" + RuoYiConfig.getProfile() + "/");
    
            /** swagger配置 */
            /**
             * 映射配置
             *      "/swagger-ui/**"访问的地址。
             *      "classpath:/META-INF/resources/webjars/springfox-swagger-ui/"找到对应的路径在jar包中。
             *      因为默认情况下swagger ui首页是英文版的但是可以对它做一些国际化的操作。
             */
            registry.addResourceHandler("/swagger-ui/**")
                    .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
                    .setCacheControl(CacheControl.maxAge(5, TimeUnit.HOURS).cachePublic());;
        }
  2. SwaggerConfigswagger配置类
    package com.ruoyi.web.core.config;
    
    import java.util.ArrayList;
    import java.util.List;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import com.ruoyi.common.config.RuoYiConfig;
    import io.swagger.annotations.ApiOperation;
    import io.swagger.models.auth.In;
    import springfox.documentation.builders.ApiInfoBuilder;
    import springfox.documentation.builders.PathSelectors;
    import springfox.documentation.builders.RequestHandlerSelectors;
    import springfox.documentation.service.ApiInfo;
    import springfox.documentation.service.ApiKey;
    import springfox.documentation.service.AuthorizationScope;
    import springfox.documentation.service.Contact;
    import springfox.documentation.service.SecurityReference;
    import springfox.documentation.service.SecurityScheme;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spi.service.contexts.SecurityContext;
    import springfox.documentation.spring.web.plugins.Docket;
    
    /**
     * Swagger2的接口配置
     */
    @Configuration
    public class SwaggerConfig
    {
        /**
         * 系统基础配置。
         * 读取项目相关配置文件常用的几个属性。
         * */
        @Autowired
        private RuoYiConfig ruoyiConfig;
    
        /** 是否开启swagger */
        @Value("${swagger.enabled}")
        private boolean enabled;
    
        /**
         * 设置请求的统一前缀。
         * 即使用swagger ui页面调用接口进行测试时请求url都会拼接这样的一个前缀。不然就映射不到后台来了因为前端有对应的路由控制。
         * 为什么需要请求前缀呢因为路由有映射。
         * 当然这个是可以改的可根据实际情况去调整。
         * */
        @Value("${swagger.pathMapping}")
        private String pathMapping;
    
        /**
         * 创建API
         */
        @Bean
        public Docket createRestApi()
        {
            // 版本DocumentationType.OAS_30
            return new Docket(DocumentationType.OAS_30)
                    // 是否启用Swagger
                    .enable(enabled)
                    // 用来创建该API的基本信息展示在文档的页面中自定义展示的信息
                    .apiInfo(apiInfo())
                    // 设置哪些接口暴露给Swagger展示
                    .select()
                    // 暴露方式1扫描所有有注解的api用这种方式更灵活
                    .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                    // 暴露方式2扫描指定包中的swagger注解
                    // .apis(RequestHandlerSelectors.basePackage("com.ruoyi.project.tool.swagger"))
                    // 暴露方式3扫描所有 .apis(RequestHandlerSelectors.any())
                    .paths(PathSelectors.any())
                    .build()
                    /* 设置安全模式swagger可以设置访问token */
                    /**
                     * 默认情况下直接访问会提示没有权限,所以需要设置一下安全模式即页面中的” Authorize按钮 ”。
                     * 点击“ Authorize按钮 ”可以看到接口需要哪些属性。
                     * 可以按实际情况传更多的参数。
                     */
                    .securitySchemes(securitySchemes())
                    .securityContexts(securityContexts())
                    .pathMapping(pathMapping);
        }
    
        /**
         * 安全模式这里指定token通过Authorization头请求头传递
         */
        private List<SecurityScheme> securitySchemes()
        {
            List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>();
            apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue()));
            return apiKeyList;
        }
    
        /**
         * 安全上下文
         */
        private List<SecurityContext> securityContexts()
        {
            List<SecurityContext> securityContexts = new ArrayList<>();
            securityContexts.add(
                    SecurityContext.builder()
                            .securityReferences(defaultAuth())
                            .operationSelector(o -> o.requestMappingPattern().matches("/.*"))
                            .build());
            return securityContexts;
        }
    
        /**
         * 默认的安全上引用
         */
        private List<SecurityReference> defaultAuth()
        {
            AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
            AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
            authorizationScopes[0] = authorizationScope;
            List<SecurityReference> securityReferences = new ArrayList<>();
            securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
            return securityReferences;
        }
    
        /**
         * 添加摘要信息。
         * 自定义展示的api基本信息。
         */
        private ApiInfo apiInfo()
        {
            // 用ApiInfoBuilder进行定制
            return new ApiInfoBuilder()
                    // 设置标题
                    .title("标题若依管理系统_接口文档")
                    // 描述
                    .description("描述用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
                    // 作者信息
                    .contact(new Contact(ruoyiConfig.getName(), null, null))
                    // 版本
                    .version("版本号:" + ruoyiConfig.getVersion())
                    .build();
        }
    }
    
    yH5BAAAAAAALAAAAAAOAA4AAAIMhI+py+0Po5y02qsKADs=
  3. RuoYiConfig系统基础配置
    /**
     * 读取项目相关配置。
     * 基础配置对应配置文件中的常用的几个属性。
     */
    @Component
    @ConfigurationProperties(prefix = "ruoyi")
    public class RuoYiConfig
    {
        /** 项目名称 */
        private String name;
    
        /** 版本 */
        private String version;
    
        /** 版权年份 */
        private String copyrightYear;
    
        /** 实例演示开关 */
        private boolean demoEnabled;
    
        /** 上传路径 */
        private static String profile;
    
        /** 获取地址开关 */
        private static boolean addressEnabled;
    
        /** 验证码类型 */
        private static String captchaType;
    
       /**
         * 获取导入上传路径
         */
        public static String getImportPath()
        {
            return getProfile() + "/import";
        }
    
        /**
         * 获取头像上传路径
         */
        public static String getAvatarPath()
        {
            return getProfile() + "/avatar";
        }
    
        /**
         * 获取下载路径
         */
        public static String getDownloadPath()
        {
            return getProfile() + "/download/";
        }
    
        /**
         * 获取上传路径
         */
        public static String getUploadPath()
        {
            return getProfile() + "/upload";
        }
    }
    
  4. application.yml
    # 项目相关配置
    ruoyi:
      # 名称
      name: RuoYi
      # 版本
      version: 3.8.6
      # 版权年份
      copyrightYear: 2023
      # 实例演示开关
      demoEnabled: true
      # 文件路径 示例 Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath
      profile: D:/ruoyi/uploadPath
      # 获取ip地址开关
      addressEnabled: false
      # 验证码类型 math 数字计算 char 字符验证
      captchaType: math
  5. SwaggerConfig#securitySchemes安全模式这里指定token通过Authorization头请求头传递
        /**
         * 安全模式这里指定token通过Authorization头请求头传递
         */
        private List<SecurityScheme> securitySchemes()
        {
            List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>();
            apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue()));
            return apiKeyList;
        }

如何汉化系统接口Swagger

        想必很多小伙伴都曾经使用过Swagger但是打开UI界面是纯英文的界面并不太友好作为国人还是习惯中文界面。

  1. 找到m2/repository/io/springfox/springfox-swagger-ui/x.x.x/springfox-swagger-ui-x.x.x.jar
  2. 修改对应springfox-swagger-ui-x.x.x.jar包内resources目录下swagger-ui.html添加如下JS代码
    <!-- 选择中文版 -->
    <script src='webjars/springfox-swagger-ui/lang/translator.js' type='text/javascript'></script>
    <script src='webjars/springfox-swagger-ui/lang/zh-cn.js' type='text/javascript'></script>
    
  3.  本地修改结束后在覆盖压缩包文件重启就实现汉化了

6 编码案例


@Api("用户信息管理")
public class TestController extends BaseController{
    // 暴露注解
    @ApiOperation("获取用户列表")
    // 参数注解
    /**
     * name参数
     * value显示的文本
     * required是否必填
     * dataType数据类型
     * paramType参数类型。如path对应的是getUser(@PathVariable Integer userId)中的@PathVariable传参方式。
     * dataTypeClass数据类型
     */
    @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
    public R<UserEntity> getUser(@PathVariable Integer userId)
    {
        List<UserEntity> userList = new ArrayList<UserEntity>(users.values());
        return R.ok(userList);
    }
}

 完整代码

/**
 * swagger 用户测试方法
 * 
 * @author ruoyi
 */
@Api("用户信息管理")
@RestController
@RequestMapping("/test/user")
public class TestController extends BaseController
{
    private final static Map<Integer, UserEntity> users = new LinkedHashMap<Integer, UserEntity>();
    {
        users.put(1, new UserEntity(1, "admin", "admin123", "15888888888"));
        users.put(2, new UserEntity(2, "ry", "admin123", "15666666666"));
    }

    @ApiOperation("获取用户列表")
    @GetMapping("/list")
    public R<List<UserEntity>> userList()
    {
        List<UserEntity> userList = new ArrayList<UserEntity>(users.values());
        return R.ok(userList);
    }

    @ApiOperation("获取用户详细")
    /**
     * name参数
     * value显示的文本
     * required是否必填
     * dataType数据类型
     * paramType参数类型。如path对应的是getUser(@PathVariable Integer userId)中的@PathVariable传参方式。
     * dataTypeClass数据类型
     */
    @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
    @GetMapping("/{userId}")
    public R<UserEntity> getUser(@PathVariable Integer userId)
    {
        if (!users.isEmpty() && users.containsKey(userId))
        {
            return R.ok(users.get(userId));
        }
        else
        {
            return R.fail("用户不存在");
        }
    }

    @ApiOperation("新增用户")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", dataTypeClass = Integer.class),
        @ApiImplicitParam(name = "username", value = "用户名称", dataType = "String", dataTypeClass = String.class),
        @ApiImplicitParam(name = "password", value = "用户密码", dataType = "String", dataTypeClass = String.class),
        @ApiImplicitParam(name = "mobile", value = "用户手机", dataType = "String", dataTypeClass = String.class)
    })
    @PostMapping("/save")
    public R<String> save(UserEntity user)
    {
        if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
        {
            return R.fail("用户ID不能为空");
        }
        users.put(user.getUserId(), user);
        return R.ok();
    }

    @ApiOperation("更新用户")
    @PutMapping("/update")
    public R<String> update(@RequestBody UserEntity user)
    {
        if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
        {
            return R.fail("用户ID不能为空");
        }
        if (users.isEmpty() || !users.containsKey(user.getUserId()))
        {
            return R.fail("用户不存在");
        }
        users.remove(user.getUserId());
        users.put(user.getUserId(), user);
        return R.ok();
    }

    @ApiOperation("删除用户信息")
    @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
    @DeleteMapping("/{userId}")
    public R<String> delete(@PathVariable Integer userId)
    {
        if (!users.isEmpty() && users.containsKey(userId))
        {
            users.remove(userId);
            return R.ok();
        }
        else
        {
            return R.fail("用户不存在");
        }
    }
}

/**
 * 参数类型为实体类
 */
@ApiModel(value = "UserEntity", description = "用户实体")
class UserEntity
{
    // 注解显示的文本。如果没有这个注解默认使用属性名称。
    @ApiModelProperty("用户ID")
    private Integer userId;

    @ApiModelProperty("用户名称")
    private String username;

    @ApiModelProperty("用户密码")
    private String password;

    @ApiModelProperty("用户手机")
    private String mobile;

    public UserEntity()
    {

    }

    public UserEntity(Integer userId, String username, String password, String mobile)
    {
        this.userId = userId;
        this.username = username;
        this.password = password;
        this.mobile = mobile;
    }

    // get/set方法
}

47 XSS脚本过滤详解

XSS攻击的定义

        跨站脚本攻击XSS是最普遍的Web应用安全漏洞。

2 模拟xss攻击示例1页面效果

ruoyi-ui\src\views\system\config\index.vuev-text效果正确

<!-- 添加或修改参数配置对话框 -->
    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
        <el-form-item label="参数名称" prop="configName">
          <!--
          <el-input v-model="form.configName" placeholder="请输入参数名称" />
          -->
          <!-- v-text其实是没有问题的因为它默认会给我们做一些处理。 -->
          <div v-text="form.configName"></div>
        </el-form-item>
        <el-form-item label="参数键名" prop="configKey">
          <el-input v-model="form.configKey" placeholder="请输入参数键名" />
        </el-form-item>
        <el-form-item label="参数键值" prop="configValue">
          <el-input v-model="form.configValue" placeholder="请输入参数键值" />
        </el-form-item>
        <el-form-item label="系统内置" prop="configType">
          <el-radio-group v-model="form.configType">
            <el-radio
              v-for="dict in dict.type.sys_yes_no"
              :key="dict.value"
              :label="dict.value"
            >{{dict.label}}</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">确 定</el-button>
        <el-button @click="cancel">取 消</el-button>
      </div>
    </el-dialog>

  

ruoyi-ui\src\views\system\config\index.vuev-html效果不正确。点击出现脚本。这种情况下可能会造成恶意代码没有经过特殊处理的脚本注入到html里面去进行攻击

<!-- 添加或修改参数配置对话框 -->
    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
        <el-form-item label="参数名称" prop="configName">
          <!--
          <el-input v-model="form.configName" placeholder="请输入参数名称" />
          -->
          <!-- v-text其实是没有问题的因为它默认会给我们做一些处理。 -->
          <!--<div v-text="form.configName"></div>-->
          <!-- 
              v-html有问题。
              v-html即支持标签为一个HTML类型。 
          -->
          <div v-html="form.configName"></div>
        </el-form-item>
        <el-form-item label="参数键名" prop="configKey">
          <el-input v-model="form.configKey" placeholder="请输入参数键名" />
        </el-form-item>
        <el-form-item label="参数键值" prop="configValue">
          <el-input v-model="form.configValue" placeholder="请输入参数键值" />
        </el-form-item>
        <el-form-item label="系统内置" prop="configType">
          <el-radio-group v-model="form.configType">
            <el-radio
              v-for="dict in dict.type.sys_yes_no"
              :key="dict.value"
              :label="dict.value"
            >{{dict.label}}</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">确 定</el-button>
        <el-button @click="cancel">取 消</el-button>
      </div>
    </el-dialog>

3 模拟xss攻击示例2数据库效果

数据库表 sys_conifg。如下图所示如果没有做XSS处理在数据库里面就会完整的把标签和脚本进行入库是非常危险的

4 如何在项目处理xss攻击?

  1. application.ymlxss处理开关
    # 防止XSS攻击
    xss:
      # 过滤开关
      enabled: true
      # 排除链接多个用逗号分隔
      # 即哪些不需要去过滤。
      # 因为通知公告的内容是富文本内容可能会包含一些HTML内容。
      # 所以一般排除就会排除一些富文本的url。
      # " * "表示所有
      excludes: /system/notice
      # 匹配链接
      # 即需要过滤的链接/system/*系统管理/monitor/*监控/tool/*工具
      urlPatterns: /system/*,/monitor/*,/tool/*
  2. 重启项目刷新页面
  3. 面对" 模拟xss攻击示例2 "数据库效果
  4. 面对" 模拟xss攻击示例2 "页面效果点击不再有弹出框

 5 项目处理xss攻击实现原理

  1. FilterConfig通用的过滤器的配置
    /**
     * Filter配置
     * 通用过滤器的配置。
     */
    @Configuration
    public class FilterConfig
    {
        /**
         * 获取application.yaml中的xss相关参数配置
         */
        @Value("${xss.excludes}")
        private String excludes;
    
        /**
         * 获取application.yaml中的xss相关参数配置
         */
        @Value("${xss.urlPatterns}")
        private String urlPatterns;
    
        /**
         * 这里可以添加加很多过滤器现在只有一个xss过滤器
         * 后续有其他的过滤器直接往里面加就行了
         * 这样方便统一去管理所有的过滤器。
         */
        @SuppressWarnings({ "rawtypes", "unchecked" })
        @Bean
        @ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
        public FilterRegistrationBean xssFilterRegistration()
        {
            FilterRegistrationBean registration = new FilterRegistrationBean();
            /**
             * 配置请求类型
             */
            registration.setDispatcherTypes(DispatcherType.REQUEST);
            /**
             * 配置xss核心过滤器
             */
            registration.setFilter(new XssFilter());
            /**
             * 配置需要过滤的链接
             */
            registration.addUrlPatterns(StringUtils.split(urlPatterns, ","));
            /**
             * 配置xss核心过滤器的名称随意
             */
            registration.setName("xssFilter");
            /**
             * 配置xss核心过滤器的优先级
             */
            registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
            /**
             * 配置xss核心过滤器的初始化参数
             */
            Map<String, String> initParameters = new HashMap<String, String>();
            /**
             * 配置xss核心过滤器的初始化参数 —— 排除的链接不需要过滤的链接
             */
            initParameters.put("excludes", excludes);
            registration.setInitParameters(initParameters);
            return registration;
        }
    }
  2. com.ruoyi.common.filter.XssFilter防止XSS攻击的过滤器
    /**
     * 防止XSS攻击的过滤器
     * 
     * @author ruoyi
     */
    public class XssFilter implements Filter
    {
        /**
         * 排除链接
         */
        public List<String> excludes = new ArrayList<>();
    
        /**
         * 初化方法
         */
        @Override
        public void init(FilterConfig filterConfig) throws ServletException
        {
            /**
             * 排除链接List
             */
            String tempExcludes = filterConfig.getInitParameter("excludes");
            if (StringUtils.isNotEmpty(tempExcludes))
            {
                String[] url = tempExcludes.split(",");
                for (int i = 0; url != null && i < url.length; i++)
                {
                    excludes.add(url[i]);
                }
            }
        }
    
        /**
         * 核心处理
         * @param request
         * @param response
         * @param chain
         * @throws IOException
         * @throws ServletException
         */
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException
        {
            HttpServletRequest req = (HttpServletRequest) request;
            HttpServletResponse resp = (HttpServletResponse) response;
            if (handleExcludeURL(req, resp))
            {
                /**
                 * 排除链接正常执行
                 */
                chain.doFilter(request, response);
                return;
            }
            /**
             * xss攻击的处理
             */
            XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
            chain.doFilter(xssRequest, response);
        }
    
        private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response)
        {
            /**
             * 获取请求url
             */
            String url = request.getServletPath();
            String method = request.getMethod();
            // GET DELETE 不过滤
            if (method == null || HttpMethod.GET.matches(method) || HttpMethod.DELETE.matches(method))
            {
                return true;
            }
            return StringUtils.matches(url, excludes);
        }
    
        @Override
        public void destroy()
        {
    
        }
    }
  3. XssHttpServletRequestWrapperXSS过滤处理
    /**
     * XSS过滤处理
     */
    public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
    {
        /**
         * @param request
         */
        public XssHttpServletRequestWrapper(HttpServletRequest request)
        {
            super(request);
        }
    
        /**
         * 处理非json类型
         * @param name
         * @return
         */
        @Override
        public String[] getParameterValues(String name)
        {
            /**
             * 获取所有请求参数值
             */
            String[] values = super.getParameterValues(name);
            if (values != null)
            {
                int length = values.length;
                String[] escapesValues = new String[length];
                for (int i = 0; i < length; i++)
                {
                    // 防xss攻击和过滤前后空格
                    escapesValues[i] = EscapeUtil.clean(values[i]).trim();
                }
                return escapesValues;
            }
            return super.getParameterValues(name);
        }
    
        /**
         * 处理json类型
         */
        @Override
        public ServletInputStream getInputStream() throws IOException
        {
            // 非json类型直接返回
            if (!isJsonRequest())
            {
                return super.getInputStream();
            }
    
            // 为空直接返回
            String json = IOUtils.toString(super.getInputStream(), "utf-8");
            if (StringUtils.isEmpty(json))
            {
                return super.getInputStream();
            }
    
            // xss过滤
            json = EscapeUtil.clean(json).trim();
            byte[] jsonBytes = json.getBytes("utf-8");
            final ByteArrayInputStream bis = new ByteArrayInputStream(jsonBytes);
            return new ServletInputStream()
            {
                @Override
                public boolean isFinished()
                {
                    return true;
                }
    
                @Override
                public boolean isReady()
                {
                    return true;
                }
    
                @Override
                public int available() throws IOException
                {
                    return jsonBytes.length;
                }
    
                @Override
                public void setReadListener(ReadListener readListener)
                {
                }
    
                @Override
                public int read() throws IOException
                {
                    return bis.read();
                }
            };
        }
    
        /**
         * 是否是Json请求
         * 
         * @param request
         */
        public boolean isJsonRequest()
        {
            String header = super.getHeader(HttpHeaders.CONTENT_TYPE);
            return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
        }
    }
  4. EscapeUtil#clean清除所有HTML标签但是不删除标签内的内容
        /**
         * 清除所有HTML标签但是不删除标签内的内容
         * 
         * @param content 文本
         * @return 清除标签后的文本
         */
        public static String clean(String content)
        {
            return new HTMLFilter().filter(content);
        }

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: vue