parent
593e14f3a9
commit
507f55f3c9
51
README.md
51
README.md
|
@ -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 自动生成数据库文档
|
||||||
|
|
||||||
## 在线体验
|
## 在线体验
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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/*
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 的请求
|
||||||
|
|
|
@ -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 的请求
|
||||||
|
|
Loading…
Reference in New Issue