1. Xss 的完成

2. 完善 README 文档
This commit is contained in:
YunaiV 2021-02-22 01:01:52 +08:00
parent 593e14f3a9
commit 507f55f3c9
7 changed files with 88 additions and 176 deletions

View File

@ -6,36 +6,45 @@
* 前端采用 [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)。 * 前端采用 [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)。
* 后端采用 Spring Boot、MySQL、Redis。 * 后端采用 Spring Boot、MySQL、Redis。
* 权限认证使用 Spring Security & JWT支持多终端认证系统。 * 权限认证使用 Spring Security & Token,支持多终端认证系统。
* 支持加载动态权限菜单,多方式轻松权限控制。 * 支持加载动态权限菜单,多方式轻松权限控制。
* 高效率开发,使用代码生成器可以一键生成前后端代码。 * 高效率开发,使用代码生成器可以一键生成前后端代码。
## 内置功能 ## 内置功能
分成 **业务****技术** 两类内置功能。 分成三种内置功能:
* 系统功能
* 基础设施
* 研发工具
### 业务功能 ### 系统功能
1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置 1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置
2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 1. 在线用户:当前系统中活跃用户状态监控
3. 岗位管理:配置系统用户所属担任职务。 1. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分
4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等 1. 菜单管理:配置系统菜单,操作权限,按钮权限标识等
5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 1. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限
6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。 1. 岗位管理:配置系统用户所属担任职务
7. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 1. 字典管理:对系统中经常使用的一些较为固定的数据进行维护
8. 登录日志:系统登录日志记录查询包含登录异常。 1. 通知公告:系统通知公告信息发布维护
9. 在线用户:当前系统中活跃用户状态监控。 1. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询
10. 通知公告:系统通知公告信息发布维护。 1. 登录日志:系统登录日志记录查询包含登录异常
## 技术功能 ### 基础设施
1. 配置管理:对系统动态配置常用参数。 1. 配置管理:对系统动态配置常用参数
2. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。 1. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志
3. 代码生成前后端代码的生成java、html、xml、sql支持CRUD下载 。 1. MySQL 监控监视当前系统数据库连接池状态可进行分析SQL找出系统性能瓶颈
4. 系统接口根据业务代码自动生成相关的api接口文档。 1. Redis 监控:监控 Redis 数据库的使用情况,使用的 Redis Key 管理
5. 服务监控监视当前系统CPU、内存、磁盘、堆栈等相关信息。 1. Java 监控:基于 Spring Boot Admin 实现 Java 应用的监控
6. 在线构建器拖动表单元素生成相应的HTML代码。 1. 链路追踪:基于 SkyWalking 实现性能监控,特别是链路的追踪
7. 连接池监视监视当前系统数据库连接池状态可进行分析SQL找出系统性能瓶颈。
### 研发工具
1. 表单构建:拖动表单元素生成相应的 HTML 代码
1. 代码生成前后端代码的生成Java、Vue、SQL支持 CRUD 下载
1. 系统接口:基于 Swagger 自动生成相关的 RESTful API 接口文档
1. 数据库文档:基于 Screw 自动生成数据库文档
## 在线体验 ## 在线体验

View File

@ -1,47 +0,0 @@
package com.ruoyi.framework.config;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.DispatcherType;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.ruoyi.common.filter.RepeatableFilter;
import com.ruoyi.common.filter.XssFilter;
import com.ruoyi.common.utils.StringUtils;
/**
* Filter配置
*
* @author ruoyi
*/
@Configuration
public class FilterConfig {
@Value("${xss.enabled}")
private String enabled;
@Value("${xss.excludes}")
private String excludes;
@Value("${xss.urlPatterns}")
private String urlPatterns;
@SuppressWarnings({"rawtypes", "unchecked"})
@Bean
public FilterRegistrationBean xssFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setDispatcherTypes(DispatcherType.REQUEST);
registration.setFilter(new XssFilter());
registration.addUrlPatterns(StringUtils.split(urlPatterns, ","));
registration.setName("xssFilter");
registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
Map<String, String> initParameters = new HashMap<String, String>();
initParameters.put("excludes", excludes);
initParameters.put("enabled", enabled);
registration.setInitParameters(initParameters);
return registration;
}
}

View File

@ -1,97 +0,0 @@
package com.ruoyi.common.filter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.utils.StringUtils;
/**
* 防止XSS攻击的过滤器
*
* @author ruoyi
*/
public class XssFilter implements Filter
{
/**
* 排除链接
*/
public List<String> excludes = new ArrayList<>();
/**
* xss过滤开关
*/
public boolean enabled = false;
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
String tempExcludes = filterConfig.getInitParameter("excludes");
String tempEnabled = filterConfig.getInitParameter("enabled");
if (StringUtils.isNotEmpty(tempExcludes))
{
String[] url = tempExcludes.split(",");
for (int i = 0; url != null && i < url.length; i++)
{
excludes.add(url[i]);
}
}
if (StringUtils.isNotEmpty(tempEnabled))
{
enabled = Boolean.valueOf(tempEnabled);
}
}
@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;
}
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
chain.doFilter(xssRequest, response);
}
private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response)
{
if (!enabled)
{
return true;
}
if (excludes == null || excludes.isEmpty())
{
return false;
}
String url = request.getServletPath();
for (String pattern : excludes)
{
Pattern p = Pattern.compile("^" + pattern);
Matcher m = p.matcher(url);
if (m.find())
{
return true;
}
}
return false;
}
@Override
public void destroy()
{
}
}

View File

@ -33,12 +33,3 @@ logging:
level: level:
com.ruoyi: debug com.ruoyi: debug
org.springframework: warn org.springframework: warn
# 防止XSS攻击
xss:
# 过滤开关
enabled: true
# 排除链接(多个用逗号分隔)
excludes: /system/notice/*
# 匹配链接
urlPatterns: /system/*,/monitor/*,/tool/*

View File

@ -1,6 +1,8 @@
package cn.iocoder.dashboard.framework.web.core.filter; package cn.iocoder.dashboard.framework.web.core.filter;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HTMLFilter; import cn.hutool.http.HTMLFilter;
@ -14,6 +16,7 @@ import java.io.BufferedReader;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.Map;
/** /**
* Xss 请求 Wrapper * Xss 请求 Wrapper
@ -36,7 +39,7 @@ public class XssRequestWrapper extends HttpServletRequestWrapper {
super(request); super(request);
} }
private static String filterHtml(String content) { private static String filterXss(String content) {
if (StrUtil.isEmpty(content)) { if (StrUtil.isEmpty(content)) {
return content; return content;
} }
@ -59,7 +62,7 @@ public class XssRequestWrapper extends HttpServletRequestWrapper {
// 读取内容并过滤 // 读取内容并过滤
String content = IoUtil.readUtf8(super.getInputStream()); String content = IoUtil.readUtf8(super.getInputStream());
content = filterHtml(content); content = filterXss(content);
final ByteArrayInputStream newInputStream = new ByteArrayInputStream(content.getBytes()); final ByteArrayInputStream newInputStream = new ByteArrayInputStream(content.getBytes());
// 返回 ServletInputStream // 返回 ServletInputStream
return new ServletInputStream() { return new ServletInputStream() {
@ -87,6 +90,47 @@ public class XssRequestWrapper extends HttpServletRequestWrapper {
// ========== Param 相关 ========== // ========== Param 相关 ==========
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
return filterXss(value);
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
if (ArrayUtil.isEmpty(values)) {
return values;
}
// 过滤处理
for (int i = 0; i < values.length; i++) {
values[i] = filterXss(values[i]);
}
return values;
}
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> valueMap = super.getParameterMap();
if (CollUtil.isEmpty(valueMap)) {
return valueMap;
}
// 过滤处理
for (Map.Entry<String, String[]> entry : valueMap.entrySet()) {
String[] values = entry.getValue();
for (int i = 0; i < values.length; i++) {
values[i] = filterXss(values[i]);
}
}
return valueMap;
}
// ========== Header 相关 ========== // ========== Header 相关 ==========
@Override
public String getHeader(String name) {
String value = super.getHeader(name);
return filterXss(value);
}
} }

View File

@ -87,6 +87,7 @@ apollo:
management: management:
endpoints: endpoints:
web: web:
base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator
exposure: exposure:
include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。
@ -131,3 +132,8 @@ yudao:
codegen: codegen:
base-package: ${yudao.info.base-package}.modules base-package: ${yudao.info.base-package}.modules
db-schemas: ${spring.datasource.name} db-schemas: ${spring.datasource.name}
xss:
enable: true
exclude-urls: # 如下两个 url仅仅是为了演示去掉配置也没关系
- ${spring.boot.admin.context-path}/** # 不处理 Spring Boot Admin 的请求
- ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求

View File

@ -87,6 +87,7 @@ apollo:
management: management:
endpoints: endpoints:
web: web:
base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator
exposure: exposure:
include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。
@ -131,3 +132,8 @@ yudao:
codegen: codegen:
base-package: ${yudao.info.base-package}.modules base-package: ${yudao.info.base-package}.modules
db-schemas: ${spring.datasource.name} db-schemas: ${spring.datasource.name}
xss:
enable: true
exclude-urls: # 如下两个 url仅仅是为了演示去掉配置也没关系
- ${spring.boot.admin.context-path}/** # 不处理 Spring Boot Admin 的请求
- ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求