# 认证核心机制 **本文引用的文件** - [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) - [AuthLoginUser.java](file://crm-auth/src/main/java/com/crm/auth/security/AuthLoginUser.java) - [PermissionResolver.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java) - [PermissionResolverImpl.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java) - [PermissionGrant.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java) - [DataVisibility.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibility.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [DataScopeLevel.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java) - [PermissionConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/PermissionConfig.java) - [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java) - [IAuthService.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) - [AuthIdentity.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/AuthIdentity.java) - [AuthUser.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/AuthUser.java) - [IAuthIdentityService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthIdentityService.java) - [AuthIdentityServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthIdentityServiceImpl.java) - [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java) - [IBaseService.java](file://crm-base/src/main/java/com/crm/base/service/IBaseService.java) - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [SecurityExceptionHandlers.java](file://crm-auth/src/main/java/com/crm/auth/security/SecurityExceptionHandlers.java) - [AuthConstants.java](file://crm-auth/src/main/java/com/crm/auth/constant/AuthConstants.java) - [application.yml](file://crm-auth/src/main/resources/application.yml) ## 更新摘要 **变更内容** - 重构认证流程:引入统一的locateUser()方法,简化用户定位逻辑 - 改进身份管理:增强孤儿身份处理机制,支持身份绑定重定向 - 优化登录流程:分离事务内外操作,提升性能和数据一致性 - 完善第三方登录:支持跨平台身份合一和自动注册功能 ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖关系分析](#依赖关系分析) 7. [性能考虑](#性能考虑) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) 10. [附录:配置示例与最佳实践](#附录配置示例与最佳实践) ## 简介 本技术文档聚焦于认证核心机制,围绕JWT令牌的生成、验证与刷新、安全过滤器链(请求拦截、用户身份解析、权限校验)、以及会话管理与并发控制等高级特性进行系统化说明。文档同时给出完整的配置要点与故障排查建议,帮助读者快速理解并落地实现。 **更新** 本次更新重点介绍了重构后的认证流程,包括统一的locateUser()方法、改进的身份管理机制和孤儿身份处理功能,显著提升了系统的可维护性和用户体验。 ## 项目结构 认证相关代码主要位于 crm-auth 模块中,关键目录与职责如下: - config:安全配置类,定义过滤器链、跨域、授权策略等 - security:安全核心组件,包括JWT过滤器、令牌服务、登录用户上下文、权限解析器、数据范围拦截器、异常处理器 - controller:认证入口控制器,提供登录、登出、刷新等接口 - service:认证业务逻辑,封装用户校验、角色权限加载、第三方登录等 - domain:领域模型,包括用户实体、身份绑定、DTO等 - constant:常量定义,如令牌前缀、过期时间、错误码等 - resources:应用配置文件,包含JWT、Redis、安全策略等参数 ```mermaid graph TB subgraph "crm-auth" C["config/SecurityConfig"] --> F["security/JwtAuthenticationFilter"] F --> T["security/TokenService"] F --> U["security/AuthLoginUser"] F --> PR["security/PermissionResolver"] PR --> PRI["security/PermissionResolverImpl"] PRI --> PG["security/PermissionGrant"] F --> DSI["security/DataScopeInterceptor"] F --> SEH["security/SecurityExceptionHandlers"] Ctrl["controller/AuthController"] --> Svc["service/IAuthService + impl/AuthServiceImpl"] Svc --> DB["持久层(用户/角色/菜单)"] T --> Redis["缓存(Redis)"] Svc --> AIS["service/impl/AuthIdentityServiceImpl"] AIS --> AI["domain/entity/AuthIdentity"] end subgraph "crm-base" DV["security/DataVisibility"] DVC["security/DataVisibilityContext"] DSL["security/DataScopeLevel"] BS["service/impl/BaseServiceImpl"] end PRI --> DV PRI --> DVC PRI --> DSL BS --> IBS["service/IBaseService"] ``` **图表来源** - [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) - [AuthLoginUser.java](file://crm-auth/src/main/java/com/crm/auth/security/AuthLoginUser.java) - [PermissionResolver.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java) - [PermissionResolverImpl.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java) - [PermissionGrant.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java) - [DataVisibility.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibility.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [DataScopeLevel.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java) - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [SecurityExceptionHandlers.java](file://crm-auth/src/main/java/com/crm/auth/security/SecurityExceptionHandlers.java) - [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java) - [IAuthService.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) - [AuthIdentity.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/AuthIdentity.java) - [AuthUser.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/AuthUser.java) - [IAuthIdentityService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthIdentityService.java) - [AuthIdentityServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthIdentityServiceImpl.java) - [BaseServiceImpl.java](file://crm-base/src/main/java/com/crm/base/service/impl/BaseServiceImpl.java) - [IBaseService.java](file://crm-base/src/main/java/com/crm/base/service/IBaseService.java) ## 核心组件 - 安全配置(SecurityConfig):注册过滤器链、白名单路径、跨域、授权规则等 - JWT过滤器(JwtAuthenticationFilter):从请求头提取令牌、校验签名、构建认证上下文 - 令牌服务(TokenService):负责JWT签发、解析、刷新、黑名单/在线会话管理 - 登录用户(AuthLoginUser):承载当前用户身份、角色、权限、数据范围等上下文信息 - **权限解析器(PermissionResolver)**:实现fail-closed安全策略,一次解析用户全部授权信息 - **权限授予对象(PermissionGrant)**:不可变的价值对象,封装数据可见性、权限码并集、角色编码 - **数据可见性(DataVisibility)**:表示用户可访问的数据范围,支持多种档位 - **数据可见性上下文(DataVisibilityContext)**:ThreadLocal存储请求级数据范围 - **身份管理服务(IAuthIdentityService)**:管理三方身份绑定和孤儿身份处理 - **统一用户定位(locateUser)**:重构后的用户定位方法,支持身份绑定和手机号匹配 - 数据范围拦截器(DataScopeInterceptor):基于注解或上下文注入SQL数据范围条件 - 异常处理器(SecurityExceptionHandlers):统一处理认证失败、权限不足、令牌异常等 - 认证控制器(AuthController):暴露登录、登出、刷新、获取用户信息等接口 - 认证服务(IAuthService/AuthServiceImpl):封装用户校验、角色权限加载、第三方登录流程 ## 架构总览 下图展示了认证核心机制的整体架构与交互关系,涵盖请求进入、JWT校验、用户上下文构建、权限校验与数据范围过滤的关键路径。 ```mermaid sequenceDiagram participant Client as "客户端" participant Filter as "JwtAuthenticationFilter" participant TokenSvc as "TokenService" participant PermRes as "PermissionResolver" participant SecCtx as "安全上下文(AuthLoginUser)" participant DSInt as "DataScopeInterceptor" participant Ctrl as "AuthController/业务控制器" Client->>Filter : "携带Authorization : Bearer " Filter->>TokenSvc : "解析并校验JWT签名/过期" TokenSvc-->>Filter : "返回有效载荷(用户ID/角色/权限)" Filter->>PermRes : "解析用户权限(一次算清)" PermRes-->>Filter : "返回PermissionGrant(可见性+权限码+角色)" Filter->>SecCtx : "构建认证上下文(含数据范围)" Filter->>DSInt : "执行数据范围拦截" DSInt-->>Filter : "注入SQL数据范围条件" Filter->>Ctrl : "放行到目标方法" Ctrl-->>Client : "返回业务结果" ``` **图表来源** - [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) - [PermissionResolver.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java) - [PermissionResolverImpl.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java) - [PermissionGrant.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java) - [DataVisibility.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibility.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java) ## 详细组件分析 ### 重构的认证流程与统一用户定位 **更新** 认证流程经过重构,引入了统一的locateUser()方法,简化了用户定位逻辑并增强了身份管理能力。 - **统一用户定位**:locateUser()方法整合了身份绑定查询和手机号匹配逻辑,避免重复代码 - **事务分离**:将DB操作与HTTP调用分离,提升性能和数据一致性 - **孤儿身份处理**:自动检测并修复指向已删除用户的身份绑定记录 - **跨平台身份合一**:支持通过手机号关联不同平台的同一用户 ```mermaid flowchart TD A["登录请求"] --> B["authCode换取三方用户信息"] B --> C["事务外组织准入预校验"] C --> D{"本地已有匹配用户?"} D --> |是| E["直接复用用户"] D --> |否| F["查询身份绑定记录"] F --> G{"存在身份绑定?"} G --> |是| H["检查用户是否存在"] H --> |存在| I["返回已存在用户"] H --> |不存在| J["警告并继续注册"] G --> |否| K["按手机号匹配用户"] K --> L{"找到用户?"} L --> |是| M["返回匹配用户"] L --> |否| N["首登自动注册新用户"] N --> O["绑定三方身份"] O --> P["处理孤儿身份重定向"] P --> Q["返回新用户"] E --> R["更新最后登录时间"] I --> R M --> R J --> N R --> S["签发JWT令牌"] S --> T["返回登录结果"] ``` **图表来源** - [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java) - [AuthIdentityServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthIdentityServiceImpl.java) - [IAuthIdentityService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthIdentityService.java) **章节来源** - [AuthServiceImpl.java:64-93](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java#L64-L93) - [AuthServiceImpl.java:117-139](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java#L117-L139) - [AuthServiceImpl.java:149-165](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java#L149-L165) ### 身份管理与孤儿身份处理 **更新** 新增完善的身份管理机制,支持孤儿身份的自动检测和修复。 - **身份绑定表设计**:AuthIdentity实体支持多平台身份绑定,唯一约束确保身份唯一性 - **孤儿身份检测**:当身份绑定的用户被物理删除时,自动重定向到新创建的用户 - **身份绑定策略**:优先使用已绑定身份,其次按手机号匹配,最后自动注册新用户 - **审计日志**:记录孤儿身份重定向操作,便于问题追踪 ```mermaid classDiagram class AuthIdentity { +userId : Long +identityType : String +unionId : String +openId : String +mobile : String } class AuthServiceImpl { +login(type, authCode) +doLoginInTx(type, thirdUser) +resolveUser(type, thirdUser) +locateUser(type, thirdUser, identity) +registerNewUser(thirdUser) } class IAuthIdentityService { <> +getByTypeAndUnionId(type, unionId) +bind(userId, type, info) } class AuthIdentityServiceImpl { +getByTypeAndUnionId(type, unionId) +bind(userId, type, info) } AuthServiceImpl --> IAuthIdentityService : "依赖" AuthIdentityServiceImpl --> IAuthIdentityService : "实现" AuthIdentityServiceImpl --> AuthIdentity : "操作" ``` **图表来源** - [AuthIdentity.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/AuthIdentity.java) - [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java) - [IAuthIdentityService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthIdentityService.java) - [AuthIdentityServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthIdentityServiceImpl.java) **章节来源** - [AuthIdentity.java:15-53](file://crm-auth/src/main/java/com/crm/auth/domain/entity/AuthIdentity.java#L15-L53) - [AuthIdentityServiceImpl.java:15-34](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthIdentityServiceImpl.java#L15-L34) - [AuthServiceImpl.java:127-138](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java#L127-L138) ### JWT令牌生命周期与刷新机制 - 签发:登录成功后由TokenService生成访问令牌与可选的刷新令牌,写入响应头或响应体;必要时将令牌元数据(如设备指纹、IP、过期时间)存入Redis用于在线会话管理 - 校验:JwtAuthenticationFilter在每次请求时提取Authorization头,调用TokenService校验签名、有效期、是否被拉黑;通过后构建AuthLoginUser上下文 - 刷新:当访问令牌即将过期或已过期时,使用刷新令牌换取新的访问令牌;刷新过程中可校验刷新令牌有效性、设备一致性、并发限制等 - 注销:服务端维护令牌黑名单或撤销在线会话,确保立即失效 ```mermaid flowchart TD Start(["开始"]) --> Extract["从请求头提取令牌"] Extract --> Validate{"令牌有效?"} Validate --> |否| HandleInvalid["抛出认证异常/返回未授权"] Validate --> |是| BuildCtx["构建AuthLoginUser上下文"] BuildCtx --> PermResolve["权限解析(PermissionResolver)"] PermResolve --> Scope["数据范围拦截器注入SQL条件"] Scope --> Pass["放行至控制器"] Pass --> End(["结束"]) HandleInvalid --> End ``` **图表来源** - [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) - [AuthLoginUser.java](file://crm-auth/src/main/java/com/crm/auth/security/AuthLoginUser.java) - [PermissionResolver.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java) - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) **章节来源** - [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java) - [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java) - [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java) - [AuthConstants.java](file://crm-auth/src/main/java/com/crm/auth/constant/AuthConstants.java) ### 安全过滤器链与请求拦截 - 过滤器链顺序:CORS -> TraceId -> JwtAuthenticationFilter -> DataScopeInterceptor -> 业务控制器 - 白名单:静态资源、健康检查、部分公开接口可跳过JWT校验 - 鉴权:在过滤器或控制器层面根据角色/权限决定放行与否 - 异常:统一由SecurityExceptionHandlers捕获并返回标准错误格式 ```mermaid sequenceDiagram participant Client as "客户端" participant Filter as "JwtAuthenticationFilter" participant PermRes as "PermissionResolver" participant DSInt as "DataScopeInterceptor" participant Handler as "SecurityExceptionHandlers" participant Ctrl as "业务控制器" Client->>Filter : "HTTP请求" Filter->>Filter : "白名单判断/跨域处理" Filter->>Filter : "JWT解析与校验" Filter->>PermRes : "权限解析(一次算清)" PermRes-->>Filter : "返回PermissionGrant" Filter->>DSInt : "数据范围拦截" DSInt-->>Filter : "注入数据范围" Filter->>Ctrl : "放行" Ctrl-->>Client : "成功响应" Note over Filter,Handler : "若发生认证/权限异常,交由异常处理器统一处理" ``` **图表来源** - [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) - [PermissionResolver.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java) - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [SecurityExceptionHandlers.java](file://crm-auth/src/main/java/com/crm/auth/security/SecurityExceptionHandlers.java) **章节来源** - [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) - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [SecurityExceptionHandlers.java](file://crm-auth/src/main/java/com/crm/auth/security/SecurityExceptionHandlers.java) ### AuthLoginUser设计模式与会话管理 - 设计模式:采用"登录用户上下文"模式,将用户标识、角色、权限、数据范围等信息聚合为单一对象,便于在过滤器、拦截器、服务层与控制器间传递 - 会话管理:结合Redis存储在线会话元数据(如设备指纹、IP、最后活跃时间),支持单点登录、强制下线、并发登录控制 - 数据可见性:通过数据范围上下文(部门、角色、自定义范围)动态注入SQL条件,实现行级数据隔离 ```mermaid classDiagram class AuthLoginUser { +用户ID +用户名 +手机号 +头像 +构造(用户信息) } class TokenService { +签发JWT() +解析JWT() +刷新令牌() +加入黑名单() +查询在线会话() } class PermissionResolver { <> +resolve(userId) +visibleMenuTree(userId) } class PermissionResolverImpl { +resolve(userId) +visibleMenuTree(userId) -authorizedMenus(roleIds) } class PermissionGrant { +visibility : DataVisibility +permCodes : Set~String~ +roleCodes : Set~String~ +asAuthorities() } class DataVisibility { +userId : Long +primaryDeptId : Long +deptIds : Long[] +level : DataScopeLevel +expandedDeptIds : Long[] +visibilityScope() +dataOwnership() } class JwtAuthenticationFilter { +doFilter(request, response) -解析令牌() -构建上下文() } class DataScopeInterceptor { +preHandle(request, response, handler) -注入数据范围() } JwtAuthenticationFilter --> TokenService : "校验/解析" JwtAuthenticationFilter --> PermissionResolver : "权限解析" PermissionResolverImpl --> PermissionGrant : "创建" PermissionResolverImpl --> DataVisibility : "构建" DataScopeInterceptor --> DataVisibility : "读取" ``` **图表来源** - [AuthLoginUser.java](file://crm-auth/src/main/java/com/crm/auth/security/AuthLoginUser.java) - [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java) - [PermissionResolver.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java) - [PermissionResolverImpl.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java) - [PermissionGrant.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java) - [DataVisibility.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibility.java) - [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java) - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) **章节来源** - [AuthLoginUser.java](file://crm-auth/src/main/java/com/crm/auth/security/AuthLoginUser.java) - [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java) - [PermissionResolver.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java) - [PermissionResolverImpl.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java) - [PermissionGrant.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java) - [DataVisibility.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibility.java) - [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java) - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) ### 权限解析架构与Fail-Closed安全策略 - PermissionResolver接口:定义权限解析的核心方法,包括用户权限解析和菜单树构建 - PermissionResolverImpl实现:实现"用户→角色→授权→资源"的查询链,支持数据可见性计算、权限码并集、角色编码归一化 - PermissionGrant价值对象:不可变的授权事实集合,包含数据可见性、权限码并集、角色编码 - DataVisibility数据可见性:表示用户可访问的数据范围,支持SELF、DEPT、DEPT_AND_CHILDREN、ALL四种档位 - DataVisibilityContext上下文:ThreadLocal存储请求级数据范围,确保线程安全 ```mermaid flowchart TD A["用户ID"] --> B["PermissionResolver.resolve()"] B --> C["查询用户角色"] C --> D["计算数据可见性档位"] D --> E["构建DataVisibility"] C --> F["查询角色授权菜单"] F --> G["过滤按钮类型权限"] G --> H["去重权限码并集"] C --> I["收集角色编码"] E --> J["创建PermissionGrant"] H --> J I --> J J --> K["Spring Security Authorities"] ``` **图表来源** - [PermissionResolver.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java) - [PermissionResolverImpl.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java) - [PermissionGrant.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java) - [DataVisibility.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibility.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) **章节来源** - [PermissionResolver.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java) - [PermissionResolverImpl.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java) - [PermissionGrant.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java) - [DataVisibility.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibility.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [DataScopeLevel.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java) ### 认证业务流程(登录、刷新、登出) - 登录:AuthController接收登录参数,调用IAuthService/AuthServiceImpl进行用户校验、角色权限加载,成功后由TokenService签发JWT并返回 - 刷新:客户端携带刷新令牌请求刷新接口,服务端校验后签发新访问令牌 - 登出:服务端将令牌加入黑名单或移除在线会话,使旧令牌立即失效 ```mermaid sequenceDiagram participant Client as "客户端" participant Ctrl as "AuthController" participant Svc as "IAuthService/AuthServiceImpl" participant Token as "TokenService" participant PermRes as "PermissionResolver" Client->>Ctrl : "POST /auth/login" Ctrl->>Svc : "校验用户/加载角色权限" Svc-->>Ctrl : "返回用户信息" Ctrl->>Token : "签发JWT(访问/刷新)" Token-->>Ctrl : "返回令牌" Ctrl-->>Client : "登录成功响应" Client->>Ctrl : "POST /auth/refresh" Ctrl->>Token : "校验刷新令牌并签发新访问令牌" Token-->>Ctrl : "返回新令牌" Ctrl-->>Client : "刷新成功响应" Client->>Ctrl : "POST /auth/logout" Ctrl->>Token : "加入黑名单/移除在线会话" Token-->>Ctrl : "操作结果" Ctrl-->>Client : "登出成功响应" Note over PermRes : "每次请求时由JWT过滤器自动解析权限" ``` **图表来源** - [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java) - [IAuthService.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) - [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java) - [PermissionResolver.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java) **章节来源** - [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java) - [IAuthService.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) - [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java) ## 依赖关系分析 - 组件内聚与耦合: - JwtAuthenticationFilter依赖TokenService与AuthLoginUser,低耦合高内聚 - PermissionResolverImpl依赖多个Mapper和缓存,实现复杂的权限解析逻辑 - PermissionGrant是不可变对象,避免状态污染 - DataScopeInterceptor依赖AuthLoginUser的数据范围字段,避免侵入业务逻辑 - SecurityConfig集中管理过滤器链与白名单,降低分散配置风险 - **AuthServiceImpl依赖IAuthIdentityService进行身份管理,支持孤儿身份处理** - 外部依赖: - Redis用于在线会话与令牌黑名单管理 - MyBatis/数据库用于用户、角色、菜单等基础数据 - 潜在循环依赖: - 通过接口解耦(IAuthService与其实现类),避免直接循环引用 ```mermaid graph LR SC["SecurityConfig"] --> JF["JwtAuthenticationFilter"] JF --> TS["TokenService"] JF --> ALU["AuthLoginUser"] JF --> PR["PermissionResolver"] PR --> PRI["PermissionResolverImpl"] PRI --> PG["PermissionGrant"] PRI --> DV["DataVisibility"] PRI --> DVC["DataVisibilityContext"] JF --> DSI["DataScopeInterceptor"] DSI --> ALU AC["AuthController"] --> IA["IAuthService"] IA --> AIS["AuthServiceImpl"] AIS --> AISvc["IAuthIdentityService"] AISvc --> AISvcImpl["AuthIdentityServiceImpl"] TS --> Redis["Redis"] ``` **图表来源** - [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) - [AuthLoginUser.java](file://crm-auth/src/main/java/com/crm/auth/security/AuthLoginUser.java) - [PermissionResolver.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java) - [PermissionResolverImpl.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java) - [PermissionGrant.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java) - [DataVisibility.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibility.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java) - [IAuthService.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) - [IAuthIdentityService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthIdentityService.java) - [AuthIdentityServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthIdentityServiceImpl.java) ## 性能考虑 - JWT无状态校验:减少数据库查询,提升吞吐;但需配合Redis做黑名单与在线会话管理 - 令牌刷新策略:合理设置访问令牌短时效、刷新令牌长时效,降低频繁鉴权开销 - 权限解析优化:PermissionResolverImpl在一次解析中完成所有授权信息查询,避免多次数据库访问 - 数据范围优化:在拦截器阶段注入SQL条件,避免在业务层重复计算 - 缓存热点:用户角色与权限可缓存至Redis,缩短鉴权路径 - 并发控制:基于设备指纹与IP限制同一用户并发会话数,防止资源滥用 - 不可变对象:PermissionGrant和DataVisibility使用不可变设计,避免同步开销 - **事务优化:将HTTP调用移出事务,避免长时间占用数据库连接** - **身份查询优化:一次性查询身份绑定记录,避免重复数据库访问** ## 故障排查指南 - 常见错误类型: - 令牌缺失或格式错误:检查Authorization头与Bearer前缀 - 签名无效或已过期:核对密钥配置与系统时钟同步 - 权限不足:确认用户角色与接口权限映射 - 数据范围异常:检查数据范围上下文是否正确注入 - 权限解析失败:检查PermissionResolverImpl中的数据库连接和查询逻辑 - **身份绑定异常:检查AuthIdentity表的唯一约束和数据完整性** - 定位步骤: - 查看JwtAuthenticationFilter日志,确认令牌解析与校验过程 - 检查TokenService的黑名单与在线会话状态 - 确认SecurityConfig白名单与跨域配置 - 核查DataScopeInterceptor的数据范围注入逻辑 - 检查PermissionResolverImpl的权限解析流程和数据库查询 - **查看AuthServiceImpl中的孤儿身份处理日志** - 恢复措施: - 清理黑名单或重置在线会话 - 重新签发令牌并更新客户端缓存 - 修正权限映射或数据范围配置 - 修复权限解析器的数据库连接和查询逻辑 - **手动修复孤儿身份绑定记录** **章节来源** - [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) - [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java) - [DataScopeInterceptor.java](file://crm-auth/src/main/java/com/crm/auth/security/DataScopeInterceptor.java) - [SecurityExceptionHandlers.java](file://crm-auth/src/main/java/com/crm/auth/security/SecurityExceptionHandlers.java) - [PermissionResolverImpl.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java) - [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java) ## 结论 本认证核心机制以JWT为核心,结合过滤器链与数据范围拦截,实现了高效、可扩展且安全的认证与授权体系。通过TokenService与会话管理,支持令牌刷新、黑名单、并发控制等高级特性;AuthLoginUser作为统一上下文,简化了跨层身份传递。 **更新** 重构后的认证流程通过统一的locateUser()方法和完善的身份管理机制,显著提升了系统的可维护性和用户体验。孤儿身份处理功能确保了数据一致性和系统稳定性。新的权限解析架构引入了PermissionResolver接口和PermissionResolverImpl实现,采用fail-closed安全策略确保安全性。PermissionGrant不可变对象提供了线程安全的授权事实封装,DataVisibility和DataVisibilityContext实现了请求级的数据范围管理。这些改进显著提升了系统的可维护性和安全性。 合理的配置与监控能有效保障系统的稳定性与安全性。 ## 附录:配置示例与最佳实践 - JWT配置要点: - 密钥长度与算法选择(建议使用强随机密钥与RS256/HS512) - 访问令牌与刷新令牌过期时间(短效访问+长效刷新) - 令牌前缀与头部名称(如Authorization: Bearer) - 安全策略: - 白名单最小化,仅开放必要接口 - 跨域严格限定来源与方法 - 统一异常处理与错误码规范 - 权限解析采用fail-closed策略,确保解析失败即拒绝请求 - 会话与并发: - 基于Redis存储在线会话,支持设备指纹与IP绑定 - 限制同一用户并发会话数,防止账号共享 - 监控与审计: - 记录登录、刷新、登出事件 - 统计令牌校验失败率与超时情况 - 定期清理过期会话与黑名单 - 监控权限解析性能和数据库查询效率 - **监控身份绑定操作和孤儿身份处理日志** - 权限解析最佳实践: - 合理使用DataScopeLevel档位,避免过度放宽数据可见性 - 利用PermissionGrant的asAuthorities()方法统一处理权限校验 - 通过DataVisibilityContext确保线程安全的数据范围传递 - 定期审查权限配置,确保最小权限原则 - **身份管理最佳实践**: - 确保AuthIdentity表的唯一约束正确配置 - 定期检查孤儿身份记录并及时修复 - 合理设置手机号匹配的优先级和策略 - 记录所有身份绑定操作的审计日志 **章节来源** - [application.yml](file://crm-auth/src/main/resources/application.yml) - [AuthConstants.java](file://crm-auth/src/main/java/com/crm/auth/constant/AuthConstants.java) - [SecurityConfig.java](file://crm-auth/src/main/java/com/crm/auth/config/SecurityConfig.java) - [PermissionResolver.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java) - [PermissionResolverImpl.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java) - [PermissionGrant.java](file://crm-auth/src/main/java/com/crm/auth/security/PermissionGrant.java) - [DataVisibility.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibility.java) - [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java) - [AuthIdentity.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/AuthIdentity.java) - [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java)