You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

27 KiB

安全架构设计

**本文引用的文件** - [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java) - [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java) - [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java) - [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java) - [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java) - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [DataScopeTables.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeTables.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java) - [LoginUser.java](file://crm-base/src/main/java/com/crm/base/security/LoginUser.java) - [DingTalkAuthClient.java](file://crm-auth/src/main/java/com/crm/auth/service/client/DingTalkAuthClient.java) - [ThirdPartyAuthClientFactory.java](file://crm-auth/src/main/java/com/crm/auth/service/client/ThirdPartyAuthClientFactory.java) - [ThirdPartyUserInfo.java](file://crm-auth/src/main/java/com/crm/auth/service/client/ThirdPartyUserInfo.java) - [AuthService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthService.java) - [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java) - [Application.yml](file://crm-app/src/main/resources/application.yml) - [MetaObjectFillHandler.java](file://crm-base/src/main/java/com/crm/base/config/MetaObjectFillHandler.java) - [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java) - [DictGroupServiceImpl.java](file://crm-dict/src/main/java/com/crm/dict/service/impl/DictGroupServiceImpl.java) - [DictItemServiceImpl.java](file://crm-dict/src/main/java/com/crm/dict/service/impl/DictItemServiceImpl.java)

更新摘要

变更内容

  • 新增审计字段防篡改机制说明,强调客户端传入的审计字段必须显式清空
  • 增强字典模块数据完整性保护,防止恶意用户伪造创建时间、创建人等审计信息
  • 完善MyBatis-Plus自动填充机制与安全边界说明
  • 补充服务层审计字段处理的最佳实践

目录

  1. 引言
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考虑
  8. 故障排查指南
  9. 结论
  10. 附录

引言

本文件面向安全开发者与系统集成人员,系统化阐述CRM系统的安全架构设计。重点覆盖:

  • 基于JWT的认证授权机制
  • RBAC权限模型与数据权限控制(DataScope)
  • SecurityConfig配置类、JwtAuthenticationFilter过滤器链、TokenService令牌管理服务
  • 第三方登录集成(钉钉)与密码加密策略、会话管理
  • 新增:审计字段防篡改机制与数据完整性保护
  • 关键流程图与权限判断逻辑图

项目结构

安全相关代码主要分布在以下模块:

  • crm-auth:认证授权、RBAC、数据权限拦截器、第三方登录客户端
  • crm-base:通用安全上下文、数据可见性工具、注解定义、审计字段自动填充
  • crm-dict:字典管理模块,包含增强的审计字段保护机制
  • crm-app:应用入口与全局配置(如application.yml)
graph TB
subgraph "应用层"
APP["CrmAppApplication"]
YML["application.yml"]
end
subgraph "认证授权模块(crm-auth)"
SEC_CFG["SecurityConfig"]
AUTH_CTL["AuthController"]
JWT_FILT["JwtAuthenticationFilter"]
TOKEN_SVC["TokenService"]
DSCOPE_INT["DataScopeInterceptor"]
DSCOPE_TBL["DataScopeTables"]
DING["DingTalkAuthClient"]
TP_FACTORY["ThirdPartyAuthClientFactory"]
AUTH_SVC["IAuthService / AuthServiceImpl"]
end
subgraph "基础能力模块(crm-base)"
ANNO_DSCOPE["DataScope注解"]
DSCOPE_CTX["DataVisibilityContext"]
DSCOPE_HELPER["DataScopeHelper"]
LOGIN_USER["LoginUser"]
META_FILL["MetaObjectFillHandler"]
BASE_ENTITY["BaseEntity"]
end
subgraph "字典模块(crm-dict)"
DICT_GROUP_SVC["DictGroupServiceImpl"]
DICT_ITEM_SVC["DictItemServiceImpl"]
AUDIT_PROTECT["审计字段保护机制"]
end
APP --> SEC_CFG
APP --> YML
AUTH_CTL --> JWT_FILT
JWT_FILT --> TOKEN_SVC
AUTH_CTL --> AUTH_SVC
DSCOPE_INT --> DSCOPE_CTX
DSCOPE_INT --> DSCOPE_HELPER
DING --> TP_FACTORY
AUTH_SVC --> DING
META_FILL --> BASE_ENTITY
DICT_GROUP_SVC --> AUDIT_PROTECT
DICT_ITEM_SVC --> AUDIT_PROTECT

图表来源

  • SecurityConfig.java
  • JwtAuthenticationFilter.java
  • TokenService.java
  • AuthController.java
  • DataScope.java
  • DataScopeInterceptor.java
  • DataScopeTables.java
  • DataVisibilityContext.java
  • DataScopeHelper.java
  • LoginUser.java
  • DingTalkAuthClient.java
  • ThirdPartyAuthClientFactory.java
  • AuthService.java
  • AuthServiceImpl.java
  • Application.yml
  • MetaObjectFillHandler.java
  • BaseEntity.java
  • DictGroupServiceImpl.java
  • DictItemServiceImpl.java

核心组件

  • SecurityConfig:统一安全配置,注册过滤器链、跨域、白名单、鉴权规则等
  • JwtAuthenticationFilter:从请求头解析JWT并构建认证上下文
  • TokenService:生成、校验、刷新、注销令牌,维护令牌状态
  • DataScope注解与拦截器:在SQL层面注入数据范围条件,实现行级数据权限
  • 第三方登录客户端:以钉钉为例,封装OAuth流程与用户信息映射
  • LoginUser与上下文:承载当前登录用户、角色、权限、数据可见范围
  • 新增:MetaObjectFillHandler审计字段自动填充处理器
  • 新增:BaseEntity实体基类,定义标准审计字段结构

章节来源

  • SecurityConfig.java
  • JwtAuthenticationFilter.java
  • TokenService.java
  • DataScope.java
  • DataScopeInterceptor.java
  • DataScopeTables.java
  • DataVisibilityContext.java
  • LoginUser.java
  • MetaObjectFillHandler.java
  • BaseEntity.java

架构总览

下图展示认证授权主流程与数据权限拦截的关键交互,以及新增的审计字段保护机制。

sequenceDiagram
participant Client as "客户端"
participant AuthCtl as "AuthController"
participant Filter as "JwtAuthenticationFilter"
participant TokenSvc as "TokenService"
participant SecCfg as "SecurityConfig"
participant DScopeInt as "DataScopeInterceptor"
participant MetaFill as "MetaObjectFillHandler"
participant DB as "数据库"
Client->>AuthCtl : "POST /auth/login (用户名/密码或第三方code)"
AuthCtl->>TokenSvc : "签发JWT(含用户、角色、权限、数据范围)"
TokenSvc-->>AuthCtl : "返回token"
AuthCtl-->>Client : "响应{token, 过期时间}"
Client->>Filter : "携带Authorization : Bearer <token>"
Filter->>TokenSvc : "校验token有效性"
TokenSvc-->>Filter : "通过则恢复登录上下文"
Filter->>SecCfg : "按白名单/路径规则放行或继续鉴权"
SecCfg-->>Filter : "决定是否进入业务方法"
Filter->>DScopeInt : "进入数据权限拦截"
DScopeInt->>DB : "根据DataScope注解注入WHERE条件"
Note over MetaFill,DB : 审计字段保护机制<br/>客户端传入的createTime/creatorId/updaterId被显式清空
Client->>AuthCtl : "保存字典分组/项"
AuthCtl->>MetaFill : "调用save操作"
MetaFill->>DB : "仅填充null值的审计字段"
DB-->>Client : "返回受限数据集"

图表来源

  • AuthController.java
  • JwtAuthenticationFilter.java
  • TokenService.java
  • SecurityConfig.java
  • DataScopeInterceptor.java
  • MetaObjectFillHandler.java

详细组件分析

认证与授权流程(JWT + RBAC)

  • 登录接口由AuthController暴露,支持账号密码与第三方登录
  • TokenService负责JWT签发与校验,包含用户、角色、权限、数据范围等信息
  • JwtAuthenticationFilter在请求到达控制器前完成身份解析与上下文设置
  • SecurityConfig集中配置白名单、鉴权规则、跨域、CSRF等
flowchart TD
Start(["请求进入"]) --> CheckPath{"是否白名单?"}
CheckPath --> |是| Allow["直接放行"]
CheckPath --> |否| ParseToken["解析Authorization头"]
ParseToken --> Valid{"Token有效?"}
Valid --> |否| Deny["拒绝访问(未认证)"]
Valid --> |是| BuildCtx["构建登录上下文(LoginUser)"]
BuildCtx --> RBAC{"是否具备所需权限?"}
RBAC --> |否| Deny
RBAC --> |是| Next["进入业务方法"]
Next --> End(["结束"])
Allow --> End
Deny --> End

图表来源

  • AuthController.java
  • JwtAuthenticationFilter.java
  • TokenService.java
  • SecurityConfig.java

章节来源

  • AuthController.java
  • JwtAuthenticationFilter.java
  • TokenService.java
  • SecurityConfig.java

DataScope数据权限注解与拦截器

  • DataScope注解用于声明数据可见范围(如本人、本部门、本部门及子部门、全部等)
  • DataScopeInterceptor在方法执行前读取注解与当前用户上下文,拼装SQL WHERE片段
  • DataScopeTables提供表名到数据范围字段的映射,确保注入条件准确
  • DataVisibilityContext与DataScopeHelper提供上下文存取与辅助计算
classDiagram
class DataScope {
+scopeType
+deptAlias
+userAlias
}
class DataScopeInterceptor {
+preHandle(request, handler, attribute) boolean
-injectWhere(sqlBuilder, scope)
}
class DataScopeTables {
+getScopeField(table) string
}
class DataVisibilityContext {
+setScope(scope)
+getScope()
+clear()
}
class DataScopeHelper {
+buildCondition(user, scope) string
}
DataScopeInterceptor --> DataScope : "读取注解"
DataScopeInterceptor --> DataVisibilityContext : "读写上下文"
DataScopeInterceptor --> DataScopeHelper : "生成条件"
DataScopeInterceptor --> DataScopeTables : "表字段映射"

图表来源

  • DataScope.java
  • DataScopeInterceptor.java
  • DataScopeTables.java
  • DataVisibilityContext.java
  • DataScopeHelper.java

章节来源

  • DataScope.java
  • DataScopeInterceptor.java
  • DataScopeTables.java
  • DataVisibilityContext.java
  • DataScopeHelper.java

审计字段防篡改机制

新增功能:为防止客户端伪造审计信息,系统在字典模块中实现了严格的审计字段保护机制。

  • 审计字段定义:BaseEntity定义了标准的审计字段(createTime、createTime、updaterId、updateTime)
  • 自动填充机制:MetaObjectFillHandler使用strictInsertFill和strictUpdateFill,仅填充null值
  • 客户端输入防护:在DictGroupServiceImpl和DictItemServiceImpl中,显式将客户端传入的审计字段设置为null
  • 安全边界:确保只有服务端能够设置审计信息,防止恶意用户伪造创建时间、创建人等敏感信息
flowchart TD
ClientReq["客户端请求"] --> ClearAudit["清空审计字段<br/>createTime=null<br/>creatorId=null<br/>updaterId=null<br/>updateTime=null"]
ClearAudit --> ServiceLayer["服务层处理"]
ServiceLayer --> MyBatisFill["MyBatis-Plus自动填充"]
MyBatisFill --> StrictFill["strictInsertFill/strictUpdateFill<br/>仅填充null值"]
StrictFill --> ServerAudit["服务端设置审计信息<br/>createTime=当前时间<br/>creatorId=当前用户ID"]
ServerAudit --> Database["持久化到数据库"]

图表来源

  • BaseEntity.java
  • MetaObjectFillHandler.java
  • DictGroupServiceImpl.java
  • DictItemServiceImpl.java

章节来源

  • BaseEntity.java
  • MetaObjectFillHandler.java
  • DictGroupServiceImpl.java
  • DictItemServiceImpl.java

第三方登录集成(钉钉)

  • DingTalkAuthClient封装钉钉OAuth2流程,获取access_token与用户信息
  • ThirdPartyAuthClientFactory统一管理第三方登录客户端实例
  • ThirdPartyUserInfo抽象第三方用户信息,便于内部统一建模
  • AuthServiceImpl协调本地用户与第三方账户绑定、自动注册或关联
sequenceDiagram
participant Client as "客户端"
participant AuthCtl as "AuthController"
participant TPFactory as "ThirdPartyAuthClientFactory"
participant Ding as "DingTalkAuthClient"
participant AuthSrv as "AuthServiceImpl"
participant Token as "TokenService"
Client->>AuthCtl : "GET /auth/thirdparty/dingtalk?code=..."
AuthCtl->>TPFactory : "获取钉钉客户端"
TPFactory-->>AuthCtl : "DingTalkAuthClient"
AuthCtl->>Ding : "用code换取access_token与用户信息"
Ding-->>AuthCtl : "ThirdPartyUserInfo"
AuthCtl->>AuthSrv : "绑定/创建本地用户"
AuthSrv-->>AuthCtl : "返回本地用户标识"
AuthCtl->>Token : "签发JWT"
Token-->>AuthCtl : "token"
AuthCtl-->>Client : "响应{token}"

图表来源

  • AuthController.java
  • DingTalkAuthClient.java
  • ThirdPartyAuthClientFactory.java
  • ThirdPartyUserInfo.java
  • AuthService.java
  • AuthServiceImpl.java
  • TokenService.java

章节来源

  • DingTalkAuthClient.java
  • ThirdPartyAuthClientFactory.java
  • ThirdPartyUserInfo.java
  • AuthService.java
  • AuthServiceImpl.java
  • AuthController.java
  • TokenService.java

密码加密策略与会话管理

  • 密码加密:建议采用强哈希算法(如BCrypt),避免明文存储;在用户注册/修改密码时进行加盐哈希
  • 会话管理:无状态JWT为主,必要时结合Redis记录黑名单或刷新令牌;登出时将token加入黑名单或失效缓存
  • 安全配置:通过SecurityConfig启用CSRF防护、CORS策略、最小化暴露端点
  • 新增:审计字段安全:通过严格的服务端审计字段控制,确保数据完整性和可追溯性

章节来源

  • SecurityConfig.java
  • TokenService.java
  • Application.yml
  • MetaObjectFillHandler.java

依赖关系分析

  • 认证链路:AuthController依赖TokenService与第三方客户端;JwtAuthenticationFilter依赖TokenService与SecurityConfig
  • 数据权限:DataScopeInterceptor依赖DataScope注解、DataVisibilityContext、DataScopeHelper与DataScopeTables
  • 第三方登录:AuthController通过工厂模式获取具体第三方客户端,再交由服务层处理用户绑定
  • 新增:审计字段依赖:MetaObjectFillHandler依赖SecurityUtils获取当前用户信息,BaseEntity定义标准审计字段结构
graph LR
AuthCtl["AuthController"] --> TokenSvc["TokenService"]
AuthCtl --> TPFactory["ThirdPartyAuthClientFactory"]
TPFactory --> Ding["DingTalkAuthClient"]
JWT["JwtAuthenticationFilter"] --> TokenSvc
JWT --> SecCfg["SecurityConfig"]
DScopeInt["DataScopeInterceptor"] --> DSCOPE["DataScope注解"]
DScopeInt --> Ctx["DataVisibilityContext"]
DScopeInt --> Helper["DataScopeHelper"]
DScopeInt --> Tbls["DataScopeTables"]
MetaFill["MetaObjectFillHandler"] --> SecUtils["SecurityUtils"]
MetaFill --> BaseEntity["BaseEntity"]
DictSvc["DictServiceImpl"] --> MetaFill

图表来源

  • AuthController.java
  • TokenService.java
  • ThirdPartyAuthClientFactory.java
  • DingTalkAuthClient.java
  • JwtAuthenticationFilter.java
  • SecurityConfig.java
  • DataScopeInterceptor.java
  • DataScope.java
  • DataVisibilityContext.java
  • DataScopeHelper.java
  • DataScopeTables.java
  • MetaObjectFillHandler.java
  • BaseEntity.java

章节来源

  • AuthController.java
  • TokenService.java
  • ThirdPartyAuthClientFactory.java
  • DingTalkAuthClient.java
  • JwtAuthenticationFilter.java
  • SecurityConfig.java
  • DataScopeInterceptor.java
  • DataScope.java
  • DataVisibilityContext.java
  • DataScopeHelper.java
  • DataScopeTables.java
  • MetaObjectFillHandler.java
  • BaseEntity.java

性能考虑

  • JWT无状态校验:减少服务端会话存储压力,适合水平扩展
  • 数据权限SQL注入:尽量使用预编译与索引优化,避免全表扫描
  • 第三方登录限流:对钉钉回调接口做速率限制与重试退避
  • 缓存热点数据:菜单、角色、权限、部门树可缓存以提升鉴权速度
  • 新增:审计字段性能:strictInsertFill/strictUpdateFill仅在null值时填充,避免不必要的数据库操作

故障排查指南

  • 认证失败
    • 检查Authorization头格式与Token有效期
    • 确认JwtAuthenticationFilter是否正确解析并构建上下文
  • 权限不足
    • 核对SecurityConfig白名单与路径鉴权规则
    • 检查用户角色与接口所需权限是否匹配
  • 数据权限异常
    • 确认DataScope注解参数与表字段映射正确
    • 查看DataVisibilityContext中当前用户的数据范围
  • 第三方登录问题
    • 校验钉钉回调地址与密钥配置
    • 检查ThirdPartyUserInfo映射字段是否完整
  • 新增:审计字段问题
    • 检查MetaObjectFillHandler是否正确配置
    • 确认业务代码是否显式清空了客户端传入的审计字段
    • 验证BaseEntity中的审计字段注解配置

章节来源

  • JwtAuthenticationFilter.java
  • SecurityConfig.java
  • DataScopeInterceptor.java
  • DataScopeTables.java
  • DataVisibilityContext.java
  • DingTalkAuthClient.java
  • ThirdPartyUserInfo.java
  • MetaObjectFillHandler.java
  • BaseEntity.java

结论

本安全架构以JWT为核心,结合RBAC与DataScope数据权限,形成"身份认证—权限校验—数据隔离"的闭环。通过统一的SecurityConfig与过滤器链,保证安全策略的可配置性与可扩展性;通过第三方登录工厂与上下文工具,提升集成效率与可维护性。新增的审计字段防篡改机制进一步增强了数据完整性保护,确保所有审计信息的真实性和不可伪造性。建议在后续迭代中持续完善令牌刷新、审计日志与动态权限下发能力。

附录

  • 术语说明
    • JWT:JSON Web Token,用于无状态身份传递
    • RBAC:基于角色的访问控制
    • DataScope:数据范围注解,限定查询数据的可见范围
    • 新增:审计字段:记录数据创建和修改的时间、用户等元数据
  • 最佳实践
    • 敏感操作二次确认与审计
    • 最小权限原则与接口级鉴权
    • 定期轮换密钥与审查第三方接入
    • 新增:在服务层显式清空客户端传入的审计字段,确保数据安全
  • 新增:审计字段安全规范
    • 所有继承BaseEntity的实体都受审计字段保护
    • 业务代码不得直接设置createTime、creatorId、updaterId、updateTime字段
    • 使用MyBatis-Plus的strictInsertFill和strictUpdateFill机制进行安全填充