1.3.1版本发布
tiny-security 1.3.1 升级日志
发布日期:2026-08-09
升级路径:1.3.0 → 1.3.1
适用分支:springboot3(Spring Boot 3.x / JDK 17+) 和 springboot2(Spring Boot 2.x / JDK 8)
一、版本概览
1.3.1 是一个架构重构 + 性能优化 + 安全加固版本。本次更新移除了全局静态单例模式,改为 Spring 原生依赖注入;修复了会话调度线程泄露问题;优化了授权检查的 Redis 访问次数;新增了异常响应状态码控制配置项;同时移除了存在安全隐患的加密工具类。
| 维度 | 说明 |
|---|---|
| 新增特性 | 2 项(异常 HTTP 状态码强制 200、授权按需查询优化) |
| Bug 修复 | 1 项(会话调度线程泄露) |
| 破坏性变更 | 3 项(GlobalConfig 移除、AuthProperties 迁移、AESUtil/RSAUtil 删除) |
| 涉及提交 | 6 次功能性提交 + 1 次版本发布 |
| 代码变更 | +1,288 / -840 行(含测试) |
二、新增特性
2.1 异常响应 HTTP 状态码强制 200(force-http-status-200)
提交: 8199d0c
背景: 部分前端框架(如 axios)对非 2xx 状态码会触发异常拦截,导致业务错误码需要额外处理。新增此配置后,异常响应统一返回 HTTP 200,由响应体 code 字段表达真实业务错误。
配置方式:
tiny-security:
force-http-status-200: true # 默认 false行为说明:
| 配置值 | HTTP 状态码 | 响应体 code 字段 |
|---|---|---|
false(默认) |
真实错误码(401/403/409/500) | 真实业务错误码 |
true |
统一 200 | 真实业务错误码(401/403/409/500) |
兼容性: 前端判错逻辑无需改动——无论开关如何,响应体 code 字段始终保留真实业务错误码。DefaultExceptionTranslator 保留了无参构造函数,向后兼容。
2.2 授权检查按注解类型按需调用 SPI
提交: d4e9e67
背景: 1.3.0 中,一个接口即使只标注了 @RequiresRoles,授权管理器仍会同时查询角色和权限(两次 Redis 访问);反之亦然。
优化内容: DefaultAuthorizationManager 现根据注解类型按需调用 SPI:
| 接口注解 | 1.3.0 行为 | 1.3.1 行为 |
|---|---|---|
仅 @RequiresRoles |
查角色 + 查权限 | 仅查角色 |
仅 @RequiresPermissions |
查角色 + 查权限 | 仅查权限 |
| 同时标注两者 | 查角色 + 查权限 | 查角色 + 查权限 |
PermissionMode.URL |
查角色 + 查权限 | 查角色 + 查权限(URL 模式始终查权限) |
收益: 单注解场景下 Redis 访问次数减半。
三、Bug 修复
3.1 会话调度线程泄露修复
提交: 68e6c7b、3756b8e(补充单测)
问题: JDBC 会话仓储(JdbcSessionRepository)和本地缓存(LocalTimeCache)各自创建了 ScheduledExecutorService 调度线程,但在应用停机时没有真正 shutdown。LocalTimeCache.endRefreshThread() 仅将 refreshFlag 标记设为 false,线程本身仍在运行。
影响场景:
- 应用正常停机时线程未关闭
- Spring DevTools 热重启导致线程累积
- 多上下文(如 Spring MVC + WebSocket)场景下线程泄露
修复方案:
| 类 | 修复方式 |
|---|---|
JdbcSessionRepository |
实现 DisposableBean,destroy() 中调用 executorService.shutdownNow() |
SingleSessionRepository |
实现 DisposableBean,destroy() 中调用 timedCache.endRefreshThread() |
LocalTimeCache |
移除 refreshFlag 标记机制,endRefreshThread() 改为直接 executorService.shutdownNow() |
四、破坏性变更(⚠️ 升级必读)
4.1 移除 GlobalConfig / GlobalConfigUtils 全局静态单例
提交: 776dac9
变更说明:
| 项目 | 1.3.0 | 1.3.1 |
|---|---|---|
| 配置持有方式 | GlobalConfig 全局静态单例 + GlobalConfigUtils 访问器 |
Spring 容器依赖注入 |
| 初始化时机 | ContextRefreshedEvent 事件监听 |
Bean 构造时注入 |
AuthAutoConfiguration |
实现 ApplicationListener<ContextRefreshedEvent> |
移除该接口,改为构造注入 |
删除的类:
org.tinycloud.security.config.GlobalConfig(217 行)org.tinycloud.security.config.GlobalConfigUtils(66 行)
升级影响:
- 如果你的代码中直接调用了
GlobalConfig.getXxx()或GlobalConfigUtils.getGlobalConfig(),需要改为通过 Spring 注入获取对应 Bean。 - 框架内部所有拦截器、
AuthProvider已改为构造注入,框架自身使用不受影响。
4.2 AuthProperties 包路径迁移
提交: 776dac9
| 项目 | 1.3.0 | 1.3.1 |
|---|---|---|
| 所在模块 | tiny-security-boot-starter |
tiny-security-core |
| 完整路径 | org.tinycloud.security.AuthProperties |
org.tinycloud.security.config.AuthProperties |
升级影响:
- 如果你通过
import引用了AuthProperties,需要更新 import 路径。 - yml 配置前缀
tiny-security不变,无需修改配置文件。 @EnableConfigurationProperties(AuthProperties.class)注解由AuthAutoConfiguration自动处理,用户通常无感知。
4.3 移除 AESUtil 和 RSAUtil 加密工具类
提交: 7cb7eb3
删除的类:
org.tinycloud.security.util.secure.AESUtil(196 行)org.tinycloud.security.util.secure.RSAUtil(128 行)
删除原因:
- 对称/非对称加密不属于认证框架职责边界
AESUtil存在硬编码默认密钥安全隐患RSAUtil未使用 OAEP 填充,存在安全风险- 框架核心代码从未引用这两个类
保留的算法:
| 类别 | 算法 | 类名 | 状态 |
|---|---|---|---|
| 摘要算法 | MD5 / SHA-256 / SM3 | DigestUtil / SM3Hash |
✅ 保留 |
| 密码哈希 | BCrypt | BCrypt |
✅ 保留 |
升级影响: 如果你的业务代码使用了 AESUtil 或 RSAUtil,请迁移至以下替代方案:
- JDK JCA(
javax.crypto.*) - Hutool(
cn.hutool.crypto.*) - BouncyCastle
五、架构改进
5.1 引入 TinySecurityFacade 门面模式
提交: 776dac9
新增 org.tinycloud.security.TinySecurityFacade(180 行),设计参照 Sa-Token 的 StpUtil/StpLogic 模式:
AuthUtil(静态外观,用户调用不变)
↓ delegate
TinySecurityFacade(Spring Bean,构造注入依赖)
↓
SecurityContextRepository / AuthorizationEvaluator
设计要点:
AuthUtil是静态外观类,用户侧调用方式(AuthUtil.getLoginId()等)完全不变TinySecurityFacade是 Spring Bean,通过构造注入获取SecurityContextRepository- 内部依赖可测试、可替换,解决了全局静态单例不可 Mock 的问题
5.2 拦截器改为构造注入
提交: 776dac9
| 拦截器 | 1.3.0 依赖获取方式 | 1.3.1 依赖获取方式 |
|---|---|---|
AuthenticationInterceptor |
从 GlobalConfig 静态获取 |
构造注入 AuthenticationManager + SecurityContextRepository |
AuthorizationInterceptor |
从 GlobalConfig 静态获取 |
构造注入 AuthorizationManager + SecurityContextRepository + SecurityEventPublisher + AuthProperties |
六、升级指南
6.1 Maven 依赖升级
<!-- Spring Boot 3.x -->
<dependency>
<groupId>top.lxyccc</groupId>
<artifactId>tiny-security-boot3-starter</artifactId>
<version>1.3.1</version>
</dependency>6.2 升级检查清单
按以下顺序检查你的项目:
- 步骤 1: 全局搜索
GlobalConfig和GlobalConfigUtils,如有引用需改为 Spring 注入方式 - 步骤 2: 全局搜索
org.tinycloud.security.AuthProperties的 import,更新为org.tinycloud.security.config.AuthProperties - 步骤 3: 全局搜索
AESUtil和RSAUtil,如有使用迁移至 JCA / Hutool / BouncyCastle - 步骤 4: 如果自定义了
DefaultExceptionTranslator,确认是否需要传入forceHttpStatus200参数 - 步骤 5: 检查是否有代码直接依赖
LocalTimeCache.refreshFlag字段(已移除) - 步骤 6: 验证
AuthUtil调用方式未变(正常情况下无需改动)
6.3 兼容性说明
| 用户侧 API | 兼容性 |
|---|---|
AuthUtil.getLoginId() 等静态方法 |
✅ 完全兼容,调用方式不变 |
yml 配置 tiny-security.* |
✅ 完全兼容,前缀不变 |
@RequiresRoles / @RequiresPermissions |
✅ 完全兼容 |
自定义 SessionRepository |
✅ 兼容(建议实现 DisposableBean 管理线程) |
自定义 ExceptionTranslator |
✅ 兼容(DefaultExceptionTranslator 保留无参构造) |
直接使用 GlobalConfig |
❌ 已移除,需改为注入 |
直接使用 AESUtil / RSAUtil |
❌ 已移除,需迁移 |
七、提交记录
| 序号 | 提交哈希 | 日期 | 类型 | 说明 |
|---|---|---|---|---|
| 1 | d4e9e67 |
2026-07-18 | feat | 授权检查按注解类型按需调用 SPI,减少 Redis 访问 |
| 2 | 68e6c7b |
2026-07-18 | fix | 会话调度线程泄露修复(JdbcSessionRepository / SingleSessionRepository / LocalTimeCache) |
| 3 | 3756b8e |
2026-07-18 | test | 补充 SessionRepositoryLifecycleTest 生命周期单测 |
| 4 | 8199d0c |
2026-08-07 | feat | 新增 force-http-status-200 异常响应状态码配置项 |
| 5 | 7cb7eb3 |
2026-08-08 | refactor | 移除 AESUtil 和 RSAUtil 加密工具类 |
| 6 | 776dac9 |
2026-08-08 | refactor | 重构安全框架配置和依赖注入机制(移除 GlobalConfig,引入 TinySecurityFacade) |
| 7 | e54d4e8 |
2026-08-09 | release | 版本号升级至 1.3.1 |
八、致谢
感谢所有贡献者和使用者的反馈与支持。如遇升级问题,请提交 Issue。