feat: v2.5.4.90

1. 使用Mybatis Plus全面替换已有Mybatis,与Spring Boot Data JPA共存且支持同时使用。使用任何技术都可以无障碍的进行业务代码编写。
2. 整合Mybatis Plus和Spring Boot Data JPA更换数据库配置属性,一处修改即可以同时修改Mybatis Plus和Spring Boot Data JPA使用数据库类型。
3. 新增接口XSS脚本攻击过滤机制,同时支持请求参数和JSON请求体过滤。采用Ebay XSS过滤模型,进一步提升防控能力。
4. 新增SQL 注入攻击防控机制。
5. 解决eurynome-cloud-gateway和eurynome-cloud-management服务启动调用Kafka问题。
6. 解决CacheConfigException错误问题,在错误体系中增加配置参数不合理提醒,让信息反馈更加友好。
7. 解决Spring Boot Admin 不支持Java 8 时间类型问题。
8. 解决Spring Boot Admin 不显示 Git Properties 信息问题。
9. 解决修改Redis密码配置生效问题
10. 梳理dependencies依赖包,对已有依赖进行进行更合理的分类,更加便于依赖包的找寻和维护。
11. 升级依赖包版本
	- spring-boot-admin 升级至 2.5.1
	- git-commit-id-plugin 升级至 4.9.10
	- docker-maven-plugin 升级至 0.37.0
	- hutool 升级至 5.7.10
	- okhttps 升级至 3.1.4
	- JustAuth 升级至1.16.3
	- aliyun-java-sdk-core 升级至 4.5.25
	- baiducloud-java-sdk 升级至 0.10.175
	- aliyun-java-sdk-oss 升级至 3.13.1
	- cn.jpush.api 升级至 3.5.2
12. 规范项目文档,增加系统部署、数据库切换等多部分内容
13. 增加Nacos配置导入包,在没有自动部署功能支持的情况下,也可以更加方便的导入配置。
14. 替换 UI SweetAlert 过期方法,解决弹出框不会关闭问题
15. 解决授权码模式(authorization code)验证码被拦截问题
This commit is contained in:
herodotus 2021-09-02 01:03:30 +08:00
parent 6b3edef026
commit daef7d38a7
65 changed files with 4024 additions and 328 deletions

132
README.md
View File

@ -12,14 +12,15 @@
<a href="https://nacos.io/zh-cn/index.html" target="_blank"><img src="https://img.shields.io/badge/Nacos-2.0.3-brightgreen" alt="Nacos 2.0.3"></a>
<a href="./LICENSE"><img src="https://img.shields.io/badge/License-Apache--2.0-blue" alt="License Apache 2.0"></a>
<a href="https://blog.csdn.net/Pointer_v" target="_blank"><img src="https://img.shields.io/badge/Author-%E7%A0%81%E5%8C%A0%E5%90%9B-orange" alt="码匠君"></a>
<a href="#" target="_blank"><img src="https://img.shields.io/badge/Version-2.5.4.80-red" alt="Version 2.5.4.80"></a>
<a href="#" target="_blank"><img src="https://img.shields.io/badge/Version-2.5.4.90-red" alt="Version 2.5.4.90"></a>
<a href="https://gitee.com/herodotus/eurynome-cloud"><img src="https://gitee.com/herodotus/eurynome-cloud/badge/star.svg?theme=dark" alt="Gitee star"></a>
<a href="https://gitee.com/herodotus/eurynome-cloud"><img src="https://gitee.com/herodotus/eurynome-cloud/badge/fork.svg?theme=dark" alt="Gitee fork"></a>
</p>
<p align="center">
<a href="https://github.com/herodotus-cloud/eurynome-cloud">Github 仓库</a> &nbsp; | &nbsp;
<a href="https://gitee.com/herodotus/eurynome-cloud">Gitee 仓库</a>
<a href="https://gitee.com/herodotus/eurynome-cloud">Gitee 仓库</a> &nbsp; | &nbsp;
<a href="https://gitee.com/herodotus/eurynome-cloud/wikis">文档</a>
</p>
@ -49,98 +50,7 @@ Eurynome Cloud是一款企业级微服务架构和服务能力开发平台。基
## [2]、功能介绍
### 统一安全认证中心
| 功能 | 说明 |
| ------------------------ | ------------------------------------------------------------ |
| OAuth2.0 安全认证 | 支持OAuth2.0授权码模式、隐式授权码模式(简单模式)、密码模式和客户端模式四种登录模式 |
| JWT Token令牌 | 采用JWT对OAuth2 Token进行加密 |
| 自定义OAuth2页面 | 自定义OAuth2 login、confirm、error页面提升系统使用用户体验。可结合自身需求进行修改。 |
| OAuth2 登录验证码 | OAuth2登录增加验证码保护支持gif、中文、算数等类型可通过配置进行修改以及是否显示验证码控制 |
| OAuth2登录数据加密传输 | 基于AES对OAuth2登录数据进行动态加密传输可通过配置对表单参数名进行动态配置提升系统安全性 |
| 平台权限管理 | 基于RBAC模型以角色和接口为核心使用统一逻辑实现@PreAuthorize注解权限与URL权限的全面整合及动态可配置化。统一平台接口白名单IP地址白名单以及Scope绑定URL的管理。无须配置Security权限注解支持URL粒度的鉴权和用户权限的动态配置。 完美支持单体式架构、UPMS自身应用需求、分布式架构以及分布式各服务多实例等各种应用场景。完美支持单体式架构、UPMS自身应用需求、分布式架构以及分布式各服务多实例等各种应用场景。 |
| User、Client数据策略访问 | 支持OAuth2 UserDetails、ClientDetails数据直连数据库和Feign两种数据获取策略模式OAuth2直连数据库性能更优Feign访问数据服务独立可动态扩展。可通过配置动态修改具体采用哪种策略 |
| 手机短信验证码注册和登录 | 支持通过手机验证码登录认证与平台为统一体系统一返回OAuth2 Token支持服务接口鉴权。 |
| 第三方系统社交注册和登录 | 基于JustAuth实现第三方系统社交登录认证与平台为统一体系统一返回OAuth2 Token支持服务接口鉴权。所有JustAuth支持的第三方系统均支持。 |
| 微信小程序注册和登录 | 支持微信小程序登录认证与平台为统一体系统一返回OAuth2 Token支持服务接口鉴权。 |
| 其它注册和登录 | 采用策略模式对外部登录和注册进行支持,目前未支持的登录,可参考标准,动态扩展,即可支持。 |
### 统一服务访问网关
| 功能 | 说明 |
| -------------- | ------------------------------------------------------------ |
| 网关动态路由 | 基于Gateway和Nacos实现服务网关动态路由无须增加任何配置即可支持服务的发现与路由 |
| 网关服务鉴权 | 服务网关集成部分权限认证功能,提升系统安全性,降低平台压力 |
| 网关服务限流 | 基于Sentinel实现服务的限流支持基于Gateway Filter的自定义限流 |
| 动态文档聚合 | 网关动态Swagger文档聚合使用Swagger 3.0支持Knife4j增强。不同环境访问控制 |
| 统一跨域处理 | 基于Gateway实现统一跨域处理 |
| 统一错误处理 | 平台统一错误处理,支持自定义错误码体系 |
| 自定义动态路由 | 支持基于DB的动态路由管理与路由规则配置 |
### 微服务架构支撑
| 功能 | 说明 |
| ------------ | ------------------------------------------------------------ |
| 服务注册发现 | 基于Nacos实现服务的注册与发现。 |
| 服务负载均衡 | Spring Cloud Netflix停止维护使用Spring Cloud Loadbalancer全面替换Ribbon |
| 服务熔断降级 | 整合OpenFeign和Sentinel从熔断降级、系统负载保护、热点防护等多个维度来保障微服务的稳定性 |
| 统一配置中心 | 基于Nacos搭建的统一配置中心使用MySQL8支持配置文件自动导入和关键信息加密可根据文件夹名称自动分组配置。 |
| 统一日志中心 | 采用TCP直连的方式采集和发送日志集成Skywalking TraceID实现日志聚合及ELK日志分析。通过@EnableXXX注解开启或关闭日志采集功能。 |
| 分布任务调度 | 极简集成xxl-job支持分布式任务调度功能 |
| 分布事务处理 | 集成Seata支持分布式事务无代码侵入灵活便捷 |
| 分布对象存储 | 支持Minio分布式对象存储。同时集成阿里云OSS可通过@EnableXXX注解开启或关闭功能。 |
| 分布式工作流 | 以Camunda引擎为基础定义分布式工作流引擎提供自研人事信息管理以及人事管理体系与工作流用户体系的实时集成 |
### 微服务运行监控
| 功能 | 说明 |
| -------------- | ------------------------------------------------------------ |
| 服务调用链监控 | 集成Skywalking进行服务调用链的监控调用链监控深度可延伸至Undertow、数据库、Redis |
| 应用吞吐量监控 | 集成Skywalking进行应用吞吐量监控 |
| 熔断、降级监控 | 集成Sentinel进行服务的熔断、降级监控 |
| 微服务状态监控 | 集成Spring Boot Admin进行服务运行状态的监控 |
### 数据自动化处理
| 功能 | 说明 |
| ------------------- | ------------------------------------------------------------ |
| 数据模型初始化 | RBAC、OAuth2部分核心表、Camunda数据表在初始部署过程中为自动化创建 |
| 核心应用数据初始化 | RBAC、OAuth2等核心数据在初始部署过程中为自动化导入 |
| URL权限数据动态汇总 | 自动扫描URL接口作为权限汇总存入系统根据URL相关信息生成唯一ID多次导入数据不会重复。可通过配置动态开启或修改扫描内容 |
| Yml配置自动导入 | 服务所需使用的配置文件可自动根据文件夹进行分组并导入到Nacos中。 |
### 服务开发支撑
| 功能 | 说明 |
| ---------------- | ------------------------------------------------------------ |
| 通用CRUD封装 | 各种类型的代码生成器较多结合实际应用使用效果来看代码生成器在实际开发中使用频率低于理想预期。因此没有考虑提供代码生成器而是对常规的CRUD进行了多层次的封装使定制化服务的开发更加便捷。 |
| 自研两级缓存封装 | 自研基于Caffeine和Redis分布式两级缓存,完美支持JPA Hibernate二级缓存,完美支持各类查询数据缓存以及JPA @ManyToMany, @ManyToOne等关联查询。实现基于Caffeine的Hibernate二级缓存可与自研两级缓存快速切换仅使用本地缓存创建Key繁琐和分页数据无法更新的问题 |
| 多类型数据库支持 | 默认采用postgresql数据库支持MySQL、Oracle、H2等多种关系型数据库无须修改代码可动态切换。数据层同时支持Spring Data Jpa和Mybatis |
| 多消息队列支持 | 适配RabbitMQ和Kafka默认使用Kafka支持消息总线(Spring Cloud Bus) |
| 多种服务调用方式 | 默认采用OpenFeign进行服务间调用支持RestTemplate和OkHttps |
| 共享式多环境切换 | 共享式、统一化多环境配置模式Yml、Docker均采用此方式配置避免类似的服务配置、Dockerfile配置导出复制和修改的问题 |
| 多团队开发管理 | 支持多团队开发,可针对各个团队开发服务,进行单独的授权配置。 |
| 注解模型模块模式 | 除必要依赖逻辑以及强注入顺序要求的模块采用Spring SPIspring.factories机制外其它功能模块均采用@EnableXXX注解编程模型可选择性进行控制是否开启对应模块减少不必要的依赖注入和启动。 |
| 代码打包记录查询 | 对代码编译信息进行记录,可查询代码版本以及编译时间等相关信息,方便运维人员更好的掌握代码信息。 |
| 人事信息管理 | 除已有的用户体系外集成单位、部门、人员等人事管理功能满足大多数人事管理场景并与Camunda工作流用户体系无缝整合实现数据实时同步 |
### 信息发送集成
| 功能 | 说明 |
| ------------------ | ------------------------------------------------------------ |
| 微信小程序订阅消息 | 支持微信小程序订阅消息发送。提供订阅消息模版工厂,可根据自身业务需求,编写少量代码既可以拓展支持新订阅消息模版。 |
| 极光消息推送集成 | 集成极光消息推送对极光后台API进行封装封装度高、调用方便可快速与自定义业务需求整合通过@EnableXXX注解开启或关闭。 |
| 环信消息集成 | 集成环信IM和消息推送使用更加便捷可在应用中根据自定义需求快速整合和拓展IM发送手机推送消息。通过@EnableXXX注解开启或关闭。 |
| 多通道SMS集成 | 集成阿里、百度、中国移动、华为、京东、极光、网易、七牛、腾讯、又拍、云片等平台短信发送通道。可通过配置动态选择具体使用通道。支持多模版定义以及模版参数顺序控制 |
### 内容审核集成
| 功能 | 说明 |
| ------------------ | ------------------------------------------------------------ |
| 阿里云内容审核 | 集成阿里云内容审核支持文本、图片、音频、视频、网页内容审核支持同步审核、异步审核、异步Callback方式审核通过@EnableXXX注解开启或关闭。 |
| 微信小程序内容审核 | 集成微信小程序内容审核,支持文本、图片、音频内容审核,支持同步、异步审核。通过@EnableXXX注解开启或关闭。 |
| 百度证照识别 | 集成百度证照审核支持营业执照、身份证OCR识别。通过@EnableXXX注解开启或关闭。 |
| 天眼查企业信息查询 | 集成天眼查企业信息查询。通过@EnableXXX注解开启或关闭。 |
![详情见Wiki](https://gitee.com/herodotus/eurynome-cloud/wikis)
## [3]、技术栈和版本说明
@ -151,7 +61,7 @@ Eurynome Cloud是一款企业级微服务架构和服务能力开发平台。基
Spring Boot | 2.5.4
Spring Cloud | 2020.0.3
Spring Cloud Alibaba | 2021.1
Spring Boot Admin | 2.4.2
Spring Boot Admin | 2.5.1
Nacos | 2.0.3 |
Sentinel | 1.8.0 |
Seata | 1.3.0 |
@ -160,20 +70,19 @@ Seata | 1.3.0 |
### 2所涉及的相关的技术
* JSON序列化Jackson & FastJson
* 消息队列Kafka 适配RabbitMQ支持消息总线(Spring Cloud Bus)
* 数据缓存JetCache + Redis + Caffeine
* 数据库: PostgresqlMySQLOracle ...
* 前端实现Vue + Vuetify
* 持久层框架: Spring Data Jpa & Mybatis
* API网关Gateway
* 服务注册&发现和配置中心: Nacos
* 服务消费OpenFeign & RestTemplate & OkHttp3
* 持久层框架: Spring Data Jpa & Mybatis Plus
* API网关Spring Cloud Gateway
* 服务注册&发现和配置中心: Alibaba Nacos
* 服务消费Spring Cloud OpenFeign & RestTemplate & OkHttps
* 负载均衡Spring Cloud Loadbalancer
* 服务熔断&降级&限流Sentinel
* 分布式事务Seata
* 服务熔断&降级&限流Alibaba Sentinel
* 服务监控Spring Boot Admin
* 消息队列使用Spring Cloud消息总线Spring Cloud Bus 默认Kafka 适配RabbitMQ
* 链路跟踪Skywalking
* 分布式事务Seata
* 数据缓存JetCache + Redis + Caffeine
* 数据库: PostgresqlMySQLOracle ...
* JSON序列化Jackson & FastJson
* 文件服务阿里云OSS/Minio
* 数据调试p6spy
* 日志中心ELK
@ -193,17 +102,16 @@ Seata | 1.3.0 |
eurynome-cloud
├── configurations -- 配置文件脚本和统一Docker build上下文目录
├── dependencies -- 工程Maven顶级依赖统一控制版本和依赖
├── documents -- 工程相关文档
├── documents -- 工程相关文档会逐步清理统一采用Gitee Wiki
├── packages -- 基础通用依赖包
├ ├── eurynome-cloud-assistant -- Spring相关公共辅助工具、注解相关工具代码组件
├ ├── eurynome-cloud-common -- 公共工具类
├ ├── eurynome-cloud-assistant -- 辅助相关代码组件
├ ├── eurynome-cloud-data -- 数据持久化、数据缓存以及Redis等数据处理相关代码组件
├ ├── eurynome-cloud-kernel -- 微服务接入平台必备组件
├ ├── eurynome-cloud-oauth -- OAuth2通用代码
├ ├── eurynome-cloud-oauth-starter -- 自定义OAuth2 StarterAthena单体版核心Starter
├ ├── eurynome-cloud-rest -- Rest相关代码组件
├ ├── eurynome-cloud-sercurity -- Security通用代码
├ ├── eurynome-cloud-oauth -- OAuth2通用代码
├ ├── eurynome-cloud-message -- 消息队列、BUG相关代码组件
├ ├── eurynome-cloud-kernel -- 微服务接入平台必备组件
├ ├── eurynome-cloud-oauth-starter -- 自定义OAuth2 Starter
├ └── eurynome-cloud-starter -- 微服务核心Starter
├── platform -- 平台核心服务
├ ├── eurynome-cloud-gateway -- 服务网关

View File

@ -1,4 +1,4 @@
VERSION=2.5.4.80
VERSION=2.5.4.90
GATEWAY_SERVICE_NAME=eurynome-cloud-gateway
GATEWAY_SERVICE_PORT=8847
UAA_SERVICE_NAME=eurynome-cloud-uaa

230
dependencies/pom.xml vendored
View File

@ -35,7 +35,7 @@
<groupId>cn.herodotus.eurynome</groupId>
<artifactId>dependencies</artifactId>
<version>2.5.4.80</version>
<version>2.5.4.90</version>
<packaging>pom</packaging>
<name>eurynome-cloud-dependencies</name>
@ -62,43 +62,47 @@
<spring-boot-dependencies.version>2.5.4</spring-boot-dependencies.version>
<spring-cloud-dependencies.version>2020.0.3</spring-cloud-dependencies.version>
<spring-cloud-alibaba-dependencies.version>2021.1</spring-cloud-alibaba-dependencies.version>
<spring-boot-admin.version>2.5.0</spring-boot-admin.version>
<spring-boot-admin.version>2.5.1</spring-boot-admin.version>
<!--Spring Boot Dependencies中没有的Maven Plugin-->
<docker-maven-plugin.version>0.36.1</docker-maven-plugin.version>
<git-commit-id-maven-plugin.version>5.0.0</git-commit-id-maven-plugin.version>
<!--Maven Plugin 相关组件-->
<docker-maven-plugin.version>0.37.0</docker-maven-plugin.version>
<git-commit-id-plugin.version>4.9.10</git-commit-id-plugin.version>
<mapstruct-processor.version>1.4.2.Final</mapstruct-processor.version>
<!--Spring Boot Dependencies中没有的工具包-->
<!--开源通用工具包-->
<commons-collections4.version>4.4</commons-collections4.version>
<commons-text.version>1.9</commons-text.version>
<commons-beanutils.version>1.9.4</commons-beanutils.version>
<commons-io.version>2.11.0</commons-io.version>
<guava.version>30.1.1-jre</guava.version>
<hutool.version>5.7.8</hutool.version>
<antisamy.version>1.6.4</antisamy.version>
<!--Alibaba开源的工具包-->
<!-- 应用开发辅助工具组件 -->
<lombok.version>1.18.20</lombok.version>
<p6spy.version>3.9.1</p6spy.version>
<springfox.version>2.9.2</springfox.version>
<swagger.version>1.6.2</swagger.version>
<logstash-logback-encoder.version>6.6</logstash-logback-encoder.version>
<!-- 阿里巴巴开源工具依赖 -->
<alibaba-fastjson.version>1.2.75</alibaba-fastjson.version>
<alibaba-jetcache.version>2.6.0</alibaba-jetcache.version>
<alibaba-nacos.version>2.0.3</alibaba-nacos.version>
<!--Spring Boot Dependencies中没有的依赖Starter组件-->
<starter-jasypt.version>3.0.3</starter-jasypt.version>
<starter-mybatis.version>2.2.0</starter-mybatis.version>
<starter-camunda.version>7.15.0</starter-camunda.version>
<!--Spring Boot Dependencies中没有的依赖组件-->
<springfox.version>2.9.2</springfox.version>
<swagger.version>1.6.2</swagger.version>
<!-- 国内开源通用组件 -->
<hutool.version>5.7.10</hutool.version>
<okhttps.version>3.1.4</okhttps.version>
<just-auth.verison>1.16.3</just-auth.verison>
<knife4j.version>2.0.6</knife4j.version>
<p6spy.version>3.9.1</p6spy.version>
<kaptcha.version>2.3.2</kaptcha.version>
<easy-captcha.version>1.6.2</easy-captcha.version>
<okhttps.version>3.1.3</okhttps.version>
<lombok.version>1.18.20</lombok.version>
<just-auth.verison>1.16.2</just-auth.verison>
<logstash-logback-encoder.version>6.6</logstash-logback-encoder.version>
<!--第三方starter-->
<starter-jasypt.version>3.0.3</starter-jasypt.version>
<starter-camunda.version>7.15.0</starter-camunda.version>
<starter-mybatis-plus.version>3.4.3.2</starter-mybatis-plus.version>
<mybatis-plus-generator.version>3.5.0</mybatis-plus-generator.version>
<velocity.version>2.3</velocity.version>
</properties>
<!-- 管理依赖版本号,子项目不会默认依赖 -->
@ -124,6 +128,8 @@
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>${spring-boot-admin.version}</version>
</dependency>
<!-- Eurynome Cloud -->
<dependency>
<groupId>${project.groupId}</groupId>
@ -191,14 +197,29 @@
<version>${project.version}</version>
</dependency>
<!-- 通用工具组件 -->
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<!-- Maven插件相关组件 -->
<!-- https://mvnrepository.com/artifact/io.fabric8/docker-maven-plugin -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>${docker-maven-plugin.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/pl.project13.maven/git-commit-id-plugin -->
<dependency>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>${git-commit-id-plugin.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mapstruct/mapstruct-processor -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct-processor.version}</version>
</dependency>
<!-- 开源通用工具包 -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
@ -228,46 +249,46 @@
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>com.ejlchina</groupId>
<artifactId>okhttps-fastjson</artifactId>
<version>${okhttps.version}</version>
</dependency>
<dependency>
<groupId>com.ejlchina</groupId>
<artifactId>okhttps-gson</artifactId>
<version>${okhttps.version}</version>
</dependency>
<dependency>
<groupId>com.ejlchina</groupId>
<artifactId>okhttps-jackson</artifactId>
<version>${okhttps.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-yaml -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>${jackson-bom.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jsr310 -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson-bom.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jdk8 -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>${jackson-bom.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.module/jackson-module-kotlin -->
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
<version>${jackson-bom.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/me.zhyd.oauth/JustAuth -->
<!-- https://mvnrepository.com/artifact/org.owasp.antisamy/antisamy -->
<dependency>
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
<version>${just-auth.verison}</version>
<groupId>org.owasp.antisamy</groupId>
<artifactId>antisamy</artifactId>
<version>${antisamy.version}</version>
</dependency>
<!-- 应用开发辅助工具组件 -->
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
@ -290,20 +311,6 @@
<artifactId>swagger-models</artifactId>
<version>${swagger.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-spring-ui -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-ui</artifactId>
<version>${knife4j.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mapstruct/mapstruct-processor -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct-processor.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/p6spy/p6spy -->
<dependency>
<groupId>p6spy</groupId>
@ -316,18 +323,7 @@
<artifactId>logstash-logback-encoder</artifactId>
<version>${logstash-logback-encoder.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.penggle/kaptcha -->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>${kaptcha.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.whvcse/easy-captcha -->
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>${easy-captcha.version}</version>
</dependency>
<!-- 阿里巴巴依赖 -->
<dependency>
@ -348,6 +344,55 @@
<version>${alibaba-jetcache.version}</version>
</dependency>
<!-- 国内开源通用组件 -->
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>com.ejlchina</groupId>
<artifactId>okhttps-fastjson</artifactId>
<version>${okhttps.version}</version>
</dependency>
<dependency>
<groupId>com.ejlchina</groupId>
<artifactId>okhttps-gson</artifactId>
<version>${okhttps.version}</version>
</dependency>
<dependency>
<groupId>com.ejlchina</groupId>
<artifactId>okhttps-jackson</artifactId>
<version>${okhttps.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/me.zhyd.oauth/JustAuth -->
<dependency>
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
<version>${just-auth.verison}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-spring-ui -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-ui</artifactId>
<version>${knife4j.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.penggle/kaptcha -->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>${kaptcha.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.whvcse/easy-captcha -->
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>${easy-captcha.version}</version>
</dependency>
<!-- 第三方Starter -->
<dependency>
<groupId>org.camunda.bpm.springboot</groupId>
@ -360,11 +405,23 @@
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>${starter-jasypt.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${starter-mybatis.version}</version>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${starter-mybatis-plus.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-generator -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatis-plus-generator.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.velocity/velocity-engine-core -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>${velocity.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
@ -431,9 +488,9 @@
</configuration>
</plugin>
<plugin>
<groupId>io.github.git-commit-id</groupId>
<artifactId>git-commit-id-maven-plugin</artifactId>
<version>${git-commit-id-maven-plugin.version}</version>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>${git-commit-id-plugin.version}</version>
<configuration>
<!-- 检查的仓库根目录,${project.basedir}项目根目录即包含pom.xml文件的目录 -->
<dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
@ -446,8 +503,9 @@
<!-- 生成git属性文件路径及文件名默认${project.build.outputDirectory}/git.properties -->
<generateGitPropertiesFilename>${project.build.outputDirectory}/git.properties
</generateGitPropertiesFilename>
<dateFormat>yyyy-MM-dd HH:mm:ss</dateFormat>
<!-- 生成git属性文件格式默认值properties -->
<format>json</format>
<!-- <format>json</format>-->
<!-- 配置git-describe命令 -->
<gitDescribe>
<skip>false</skip>

View File

@ -27,7 +27,7 @@
<parent>
<artifactId>packages</artifactId>
<groupId>cn.herodotus.eurynome</groupId>
<version>2.5.4.80</version>
<version>2.5.4.90</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -121,6 +121,7 @@ public class HerodotusExceptionHandler {
EXCEPTION_DICTIONARY.put("MethodArgumentNotValidException", getValidationResult(ResultStatus.METHOD_ARGUMENT_NOT_VALID));
// 7*.** 对应错误
EXCEPTION_DICTIONARY.put("RedisPipelineException", getResult(ResultStatus.PIPELINE_INVALID_COMMANDS, HttpStatus.SC_INTERNAL_SERVER_ERROR));
EXCEPTION_DICTIONARY.put("CacheConfigException", getResult(ResultStatus.CACHE_CONFIG_NOT_FOUND, HttpStatus.SC_NOT_IMPLEMENTED));
// 以下是没有重新梳理过的错误
EXCEPTION_DICTIONARY.put("UsernameNotFoundException", getUnauthorizedResult(ResultStatus.USERNAME_NOT_FOUND));
EXCEPTION_DICTIONARY.put("BadCredentialsException", getUnauthorizedResult(ResultStatus.BAD_CREDENTIALS));

View File

@ -29,11 +29,11 @@
<parent>
<artifactId>packages</artifactId>
<groupId>cn.herodotus.eurynome</groupId>
<version>2.5.4.80</version>
<version>2.5.4.90</version>
</parent>
<artifactId>eurynome-cloud-common</artifactId>
<version>2.5.4.80</version>
<version>2.5.4.90</version>
<packaging>jar</packaging>
<description>结对基础通用的工具类包,此包的定位是放在任何工程中都可以使用,而且尽可能依赖少的存在上下文组件</description>
@ -85,6 +85,14 @@
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
@ -118,6 +126,17 @@
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
</dependency>
<dependency>
<groupId>org.owasp.antisamy</groupId>
<artifactId>antisamy</artifactId>
<exclusions>
<exclusion>
<artifactId>slf4j-simple</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>

View File

@ -75,6 +75,16 @@ public enum ResultStatus {
WARNING(4001, "警告"),
METHOD_NOT_ALLOWED(4105, "请求方法不支持"),
/**
* 43.** 禁止的请求与403对应
*/
SQL_INJECTION_REQUEST(4301, "疑似SQL注入请求"),
/**
* 46.** 不接受的请求与406对应
*/
REPEAT_SUBMISSION(4601, "不要重复提交"),
FREQUENT_REQUESTS(4602, "请求过于频繁请稍后再试"),
@ -88,8 +98,10 @@ public enum ResultStatus {
/**
* 7*.* 基础设施交互错误
* 71.* Redis 操作出现错误
* 72.* Cache 操作出现错误
*/
PIPELINE_INVALID_COMMANDS(7100, "Redis管道包含一个或多个无效命令"),
CACHE_CONFIG_NOT_FOUND(7200, "服务需要使用缓存,但是未找到*-cache.yaml配置"),
// TODO: 以下状态码和错误信息要重新梳理重点要看自定义错误码以及对应的HttpStatus是否合适如果发现新的没有定义的错误增加到上面

View File

@ -65,6 +65,7 @@ public class PropertyConstants {
public static final String ITEM_SPRING_APPLICATION_NAME = "spring.application.name";
public static final String ITEM_SPRING_JPA_HIBERNATE_DDL_AUTO = "spring.jpa.hibernate.ddl-auto";
public static final String ITEM_SPRING_SQL_INIT_PLATFORM = "spring.sql.init.platform";
public static final String ITEM_PLATFORM_DATA_ACCESS_STRATEGY = PROPERTY_PREFIX_PLATFORM + ".data-access-strategy";
public static final String ITEM_PLATFORM_ARCHITECTURE = PROPERTY_PREFIX_PLATFORM + ".architecture";
@ -73,6 +74,11 @@ public class PropertyConstants {
public static final String ITEM_MANAGEMENT_KAFKA_ENABLED = PROPERTY_PREFIX_MANAGEMENT_QUEUE + ".kafka.enabled";
public static final String ITEM_MANAGEMENT_LOG_CENTER_ENABLED = PROPERTY_PREFIX_MANAGEMENT_LOG_CENTER + ".server-addr";
public static final String ANNOTATION_APPLICATION_NAME = "${" + ITEM_SPRING_APPLICATION_NAME + "}";
public static final String ANNOTATION_PREFIX = "${";
public static final String ANNOTATION_SUFFIX = "}";
public static final String ANNOTATION_APPLICATION_NAME = ANNOTATION_PREFIX + ITEM_SPRING_APPLICATION_NAME + ANNOTATION_SUFFIX;
public static final String ANNOTATION_SQL_INIT_PLATFORM = ANNOTATION_PREFIX + ITEM_SPRING_SQL_INIT_PLATFORM + ANNOTATION_SUFFIX;
public static final String ANNOTATION_DEBEZIUM_ENABLED = "${herodotus.platform.debezium.enabled}";
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2019-2021 Gengwei Zheng (herodotus@aliyun.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Project Name: eurynome-cloud
* Module Name: eurynome-cloud-common
* File Name: XssStringJsonSerializer.java
* Author: gengwei.zheng
* Date: 2021/09/01 12:41:01
*/
package cn.herodotus.eurynome.common.jackson.deserializer;
import cn.herodotus.eurynome.common.utils.XssUtils;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
/**
* <p>Description: Xss Json 处理 </p>
*
* @author : gengwei.zheng
* @date : 2021/9/1 12:16
*/
public class XssStringJsonDeserializer extends JsonDeserializer<String> {
private static final Logger log = LoggerFactory.getLogger(XssStringJsonDeserializer.class);
@Override
public Class<String> handledType() {
return String.class;
}
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
String value = jsonParser.getValueAsString();
if (StringUtils.isNotBlank(value)) {
return XssUtils.cleaning(value);
}
return value;
}
}

View File

@ -24,12 +24,14 @@ package cn.herodotus.eurynome.common.utils;
import cn.herodotus.eurynome.common.jackson.FastJsonSerializerFeatureCompatibleForJackson;
import cn.herodotus.eurynome.common.jackson.SerializerFeature;
import cn.herodotus.eurynome.common.jackson.deserializer.XssStringJsonDeserializer;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -40,19 +42,19 @@ import java.util.List;
import java.util.TimeZone;
/**
* @author gengwei.zheng
* <p>Description: Jackson单例工具类 </p>
*
* @author : gengwei.zheng
* @date : 2021/9/1 12:18
*/
public class JacksonUtils {
private static final Logger logger = LoggerFactory.getLogger(JacksonUtils.class);
private static final ObjectMapper objectMapper;
private static volatile JacksonUtils INSTANCE;
private final ObjectMapper objectMapper;
public static ObjectMapper getObjectMapper() {
return objectMapper;
}
static {
private JacksonUtils() {
objectMapper = new ObjectMapper();
// 设置为中国上海时区
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
@ -68,6 +70,7 @@ public class JacksonUtils {
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 单引号处理
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);
/**
@ -77,6 +80,7 @@ public class JacksonUtils {
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
simpleModule.addDeserializer(String.class, new XssStringJsonDeserializer());
objectMapper.registerModule(simpleModule);
// 兼容fastJson 的一些空值处理
@ -90,15 +94,35 @@ public class JacksonUtils {
objectMapper.setSerializerFactory(objectMapper.getSerializerFactory().withSerializerModifier(new FastJsonSerializerFeatureCompatibleForJackson(features)));
}
private static JacksonUtils getInstance() {
if (ObjectUtils.isEmpty(INSTANCE)) {
synchronized (JacksonUtils.class) {
if (ObjectUtils.isEmpty(INSTANCE)) {
INSTANCE = new JacksonUtils();
}
}
}
return INSTANCE;
}
private ObjectMapper objectMapper() {
return this.objectMapper;
}
public static ObjectMapper getObjectMapper() {
return JacksonUtils.getInstance().objectMapper();
}
public static <T> T toObject(String json, Class<T> clazz) {
try {
return getObjectMapper().readValue(json, clazz);
} catch (JsonParseException e) {
logger.error("[JacksonUtils] |- toObject parse json error! {}", e.getMessage());
logger.error("[Eurynome] |- JacksonUtils toObject parse json error! {}", e.getMessage());
} catch (JsonMappingException e) {
logger.error("[JacksonUtils] |- toObject mapping to object error! {}", e.getMessage());
logger.error("[Eurynome] |- JacksonUtils toObject mapping to object error! {}", e.getMessage());
} catch (IOException e) {
logger.error("[JacksonUtils] |- toObject read content error! {}", e.getMessage());
logger.error("[Eurynome] |- JacksonUtils toObject read content error! {}", e.getMessage());
}
return null;
@ -108,27 +132,26 @@ public class JacksonUtils {
try {
return getObjectMapper().writeValueAsString(entity);
} catch (JsonParseException e) {
logger.error("[JacksonUtils] |- toCollection parse json error! {}", e.getMessage());
logger.error("[Eurynome] |- JacksonUtils toCollection parse json error! {}", e.getMessage());
} catch (JsonMappingException e) {
logger.error("[JacksonUtils] |- toCollection mapping to object error! {}", e.getMessage());
logger.error("[Eurynome] |- JacksonUtils toCollection mapping to object error! {}", e.getMessage());
} catch (IOException e) {
logger.error("[JacksonUtils] |- toCollection read content error! {}", e.getMessage());
logger.error("[Eurynome] |- JacksonUtils toCollection read content error! {}", e.getMessage());
}
return null;
}
@SuppressWarnings("unchecked")
public static <T> List<T> toList(String json, Class<T> clazz) {
JavaType javaType = getObjectMapper().getTypeFactory().constructParametricType(ArrayList.class, clazz);
try {
return (List<T>) getObjectMapper().readValue(json, javaType);
return getObjectMapper().readValue(json, javaType);
} catch (JsonParseException e) {
logger.error("[JacksonUtils] |- toCollection parse json error! {}", e.getMessage());
logger.error("[Eurynome] |- JacksonUtils toCollection parse json error! {}", e.getMessage());
} catch (JsonMappingException e) {
logger.error("[JacksonUtils] |- toCollection mapping to object error! {}", e.getMessage());
logger.error("[Eurynome] |- JacksonUtils toCollection mapping to object error! {}", e.getMessage());
} catch (IOException e) {
logger.error("[JacksonUtils] |- toCollection read content error! {}", e.getMessage());
logger.error("[Eurynome] |- JacksonUtils toCollection read content error! {}", e.getMessage());
}
return null;
@ -138,11 +161,11 @@ public class JacksonUtils {
try {
return getObjectMapper().readValue(json, typeReference);
} catch (JsonParseException e) {
logger.error("-| [JacksonUtils]: toCollection parse json error! {}", e.getMessage());
logger.error("-| [Eurynome]: JacksonUtils toCollection parse json error! {}", e.getMessage());
} catch (JsonMappingException e) {
logger.error("-| [JacksonUtils]: toCollection mapping to object error! {}", e.getMessage());
logger.error("-| [Eurynome]: JacksonUtils toCollection mapping to object error! {}", e.getMessage());
} catch (IOException e) {
logger.error("-| [JacksonUtils]: toCollection read content error! {}", e.getMessage());
logger.error("-| [Eurynome]: JacksonUtils toCollection read content error! {}", e.getMessage());
}
return null;

View File

@ -0,0 +1,122 @@
/*
* Copyright (c) 2019-2021 Gengwei Zheng (herodotus@aliyun.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Project Name: eurynome-cloud
* Module Name: eurynome-cloud-common
* File Name: ResourceUtils.java
* Author: gengwei.zheng
* Date: 2021/09/01 12:18:01
*/
package cn.herodotus.eurynome.common.utils;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
/**
* <p>Description: 资源查找单例工具类 </p>
*
* @author : gengwei.zheng
* @date : 2021/9/1 12:18
*/
public class ResourceUtils {
private static final Logger log = LoggerFactory.getLogger(ResourceUtils.class);
private static volatile ResourceUtils INSTANCE;
private final PathMatchingResourcePatternResolver resolver;
private ResourceUtils() {
this.resolver = new PathMatchingResourcePatternResolver();
}
private static ResourceUtils getInstance() {
if (ObjectUtils.isEmpty(INSTANCE)) {
synchronized (ResourceUtils.class) {
if (ObjectUtils.isEmpty(INSTANCE)) {
INSTANCE = new ResourceUtils();
}
}
}
return INSTANCE;
}
private PathMatchingResourcePatternResolver getResolver() {
return this.resolver;
}
public static Resource getResource(String location) {
return ResourceUtils.getInstance().getResolver().getResource(location);
}
public static Resource[] getResources(String locationPattern) throws IOException {
return ResourceUtils.getInstance().getResolver().getResources(locationPattern);
}
public static File getFile(String location) throws IOException {
return ResourceUtils.getResource(location).getFile();
}
public static InputStream getInputStream(String location) throws IOException {
return ResourceUtils.getResource(location).getInputStream();
}
public static String getFilename(String location) {
return ResourceUtils.getResource(location).getFilename();
}
public static URI getURI(String location) throws IOException {
return ResourceUtils.getResource(location).getURI();
}
public static URL getURL(String location) throws IOException {
return ResourceUtils.getResource(location).getURL();
}
public static long contentLength(String location) throws IOException {
return ResourceUtils.getResource(location).contentLength();
}
public static long lastModified(String location) throws IOException {
return ResourceUtils.getResource(location).lastModified();
}
public static boolean exists(String location) {
return ResourceUtils.getResource(location).exists();
}
public static boolean isFile(String location) {
return ResourceUtils.getResource(location).isFile();
}
public static boolean isReadable(String location) {
return ResourceUtils.getResource(location).isReadable();
}
public static boolean isOpen(String location) {
return ResourceUtils.getResource(location).isOpen();
}
}

View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2019-2021 Gengwei Zheng (herodotus@aliyun.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Project Name: eurynome-cloud
* Module Name: eurynome-cloud-common
* File Name: SQLInjectionUtils.java
* Author: gengwei.zheng
* Date: 2021/09/01 12:19:01
*/
package cn.herodotus.eurynome.common.utils;
import cn.herodotus.eurynome.common.constant.magic.SymbolConstants;
import cn.hutool.core.net.URLDecoder;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Stream;
/**
* <p>Description: SQL注入处理工具类 </p>
*
* @author : gengwei.zheng
* @date : 2021/9/1 12:19
*/
public class SQLInjectionUtils {
private static final Logger log = LoggerFactory.getLogger(SQLInjectionUtils.class);
private static final String SQL_REGEX = "\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
private static final Pattern SQL_PATTERN = Pattern.compile(SQL_REGEX, Pattern.CASE_INSENSITIVE);
private static boolean matching(String lowerValue, String param) {
if (SQL_PATTERN.matcher(param).find()) {
log.error("[Eurynome] |- The parameter contains keywords {} that do not allow SQL!", lowerValue);
return true;
}
return false;
}
private static String toLowerCase(Object obj) {
//这里需要将参数转换为小写来处理
return Optional.ofNullable(obj)
.map(Object::toString)
.map(String::toLowerCase)
.orElse("");
}
private static boolean checking(Object value) {
//这里需要将参数转换为小写来处理
String lowerValue = toLowerCase(value);
return matching(lowerValue, lowerValue);
}
/**
* get请求sql注入校验
*
* @param value 具体的检验
* @return 是否存在不合规内容
*/
public static boolean checkForGet(String value) {
//参数需要url编码
//这里需要将参数转换为小写来处理
//不改变原值
//value示例 order=asc&pageNum=1&pageSize=100&parentId=0
String lowerValue = URLDecoder.decode(value, StandardCharsets.UTF_8).toLowerCase();
//获取到请求中所有参数值-取每个key=value组合第一个等号后面的值
return Stream.of(lowerValue.split("\\&"))
.map(kp -> kp.substring(kp.indexOf(SymbolConstants.EQUAL) + 1))
.parallel()
.anyMatch(param -> matching(lowerValue, param));
}
/**
* post请求sql注入校验
*
* @param value 具体的检验
* @return 是否存在不合规内容
*/
public static boolean checkForPost(String value) {
Object jsonObj = JSON.parse(value);
if (jsonObj instanceof JSONObject) {
JSONObject json = (JSONObject) jsonObj;
return json.entrySet().stream().parallel().anyMatch(entry -> checking(entry.getValue()));
}
if (jsonObj instanceof JSONArray) {
JSONArray json = (JSONArray) jsonObj;
return json.stream().parallel().anyMatch(SQLInjectionUtils::checking);
}
return false;
}
}

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2019-2021 Gengwei Zheng (herodotus@aliyun.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Project Name: eurynome-cloud
* Module Name: eurynome-cloud-common
* File Name: XssUtils.java
* Author: gengwei.zheng
* Date: 2021/09/01 12:21:01
*/
package cn.herodotus.eurynome.common.utils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.owasp.validator.html.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.URL;
/**
* <p>Description: Antisamy 单例 工具类 </p>
*
* @author : gengwei.zheng
* @date : 2021/9/1 12:21
*/
public class XssUtils {
private static final Logger log = LoggerFactory.getLogger(XssUtils.class);
private static volatile XssUtils INSTANCE;
private final AntiSamy antiSamy;
private XssUtils() {
Policy policy = createPolicy();
this.antiSamy = ObjectUtils.isNotEmpty(policy) ? new AntiSamy(policy) : new AntiSamy();
}
private static XssUtils getInstance() {
if (ObjectUtils.isEmpty(INSTANCE)) {
synchronized (XssUtils.class) {
if (ObjectUtils.isEmpty(INSTANCE)) {
INSTANCE = new XssUtils();
}
}
}
return INSTANCE;
}
private Policy createPolicy() {
try {
URL url = ResourceUtils.getURL("classpath:antisamy/antisamy-ebay.xml");
return Policy.getInstance(url);
} catch (IOException | PolicyException e) {
log.warn("[Eurynome] |- Antisamy create policy error! {}", e.getMessage());
return null;
}
}
private AntiSamy antiSamy() {
return antiSamy;
}
public static AntiSamy getAntiSamy() {
return XssUtils.getInstance().antiSamy();
}
public static CleanResults scan(String taintedHtml) throws ScanException, PolicyException {
return getAntiSamy().scan(taintedHtml);
}
public static String cleaning(String value) {
try {
log.trace("[Eurynome] |- Before Antisamy cleaning XSS, value is: [{}]", value);
// 使用AntiSamy清洗数据
final CleanResults cleanResults = XssUtils.scan(value);
// 获得安全的HTML输出
value = cleanResults.getCleanHTML();
// 对转义的HTML特殊字符<>"进行反转义因为AntiSamy调用scan方法时会将特殊字符转义
String result = StringEscapeUtils.unescapeHtml4(value);
log.trace("[Eurynome] |- After Antisamy cleaning XSS, value is: [{}]", value);
return result;
} catch (ScanException | PolicyException e) {
log.error("[Eurynome] |- Antisamy cleaning XSS catch error! {}", e.getMessage());
}
return value;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="anti-samy-rules">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="include" type="Include" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="directives" type="Directives"/>
<xsd:element name="common-regexps" type="CommonRegexps"/>
<xsd:element name="common-attributes" type="AttributeList"/>
<xsd:element name="global-tag-attributes" type="AttributeList"/>
<xsd:element name="dynamic-tag-attributes" type="AttributeList" minOccurs="0"/>
<xsd:element name="tags-to-encode" type="TagsToEncodeList" minOccurs="0"/>
<xsd:element name="tag-rules" type="TagRules"/>
<xsd:element name="css-rules" type="CSSRules"/>
<xsd:element name="allowed-empty-tags" type="AllowedEmptyTags" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="Include">
<xsd:attribute name="href" use="required" type="xsd:string"/>
</xsd:complexType>
<xsd:complexType name="Directives">
<xsd:sequence maxOccurs="unbounded">
<xsd:element name="directive" type="Directive" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Directive">
<xsd:attribute name="name" use="required"/>
<xsd:attribute name="value" use="required"/>
</xsd:complexType>
<xsd:complexType name="CommonRegexps">
<xsd:sequence maxOccurs="unbounded">
<xsd:element name="regexp" type="RegExp" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AttributeList">
<xsd:sequence maxOccurs="unbounded">
<xsd:element name="attribute" type="Attribute" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TagsToEncodeList">
<xsd:sequence maxOccurs="unbounded">
<xsd:element name="tag" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TagRules">
<xsd:sequence maxOccurs="unbounded">
<xsd:element name="tag" type="Tag" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Tag">
<xsd:sequence maxOccurs="unbounded">
<xsd:element name="attribute" type="Attribute" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required"/>
<xsd:attribute name="action" use="required"/>
</xsd:complexType>
<xsd:complexType name="AllowedEmptyTags">
<xsd:sequence>
<xsd:element name="literal-list" type="LiteralList" minOccurs="0"/>
</xsd:sequence>
</xsd:complexTyp