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.
20 KiB
20 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) - [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) - [AuthUserServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthUserServiceImpl.java) - [AuthIdentityServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthIdentityServiceImpl.java) - [AuthUser.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/AuthUser.java) - [AuthIdentity.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/AuthIdentity.java) - [LoginParam.java](file://crm-auth/src/main/java/com/crm/auth/domain/param/LoginParam.java) - [LoginResultDTO.java](file://crm-auth/src/main/java/com/crm/auth/domain/dto/LoginResultDTO.java) - [UserInfoDTO.java](file://crm-auth/src/main/java/com/crm/auth/domain/dto/UserInfoDTO.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) - [CorsConfig.java](file://crm-base/src/main/java/com/crm/base/config/CorsConfig.java)目录
简介
本文件面向CRM系统的认证模块,系统性阐述基于JWT的认证流程与实现细节。内容覆盖:
- SecurityConfig安全配置(登录接口放行、静态资源控制、跨域等)
- JwtAuthenticationFilter过滤器工作原理
- TokenService令牌管理服务(生成、校验、刷新)
- 用户登录验证流程与密码加密策略(BCrypt)
- 第三方登录集成(钉钉)的实现方式
- 关键流程图与代码路径指引,帮助开发者快速理解认证链路
项目结构
认证相关代码集中在crm-auth模块,围绕Spring Security构建,结合自定义过滤器与服务完成JWT鉴权;基础能力(如跨域、统一异常、工具类)在crm-base模块提供。
graph TB
subgraph "crm-auth"
A["config/SecurityConfig"] --> B["security/JwtAuthenticationFilter"]
B --> C["security/TokenService"]
D["controller/AuthController"] --> E["service/IAuthService"]
E --> F["service/impl/AuthUserServiceImpl"]
E --> G["service/impl/AuthIdentityServiceImpl"]
H["service/client/DingTalkAuthClient"] --> I["service/client/ThirdPartyAuthClientFactory"]
J["domain/entity/AuthUser"] --> K["mapper/*"]
L["domain/entity/AuthIdentity"] --> K
end
subgraph "crm-base"
M["config/CorsConfig"]
end
M --> A
图表来源
- SecurityConfig.java
- JwtAuthenticationFilter.java
- TokenService.java
- AuthController.java
- IAuthService.java
- AuthUserServiceImpl.java
- AuthIdentityServiceImpl.java
- DingTalkAuthClient.java
- ThirdPartyAuthClientFactory.java
- AuthUser.java
- AuthIdentity.java
- CorsConfig.java
章节来源
- SecurityConfig.java
- application.yml
- CorsConfig.java
核心组件
- SecurityConfig:定义HTTP访问规则、放行路径、跨域、会话策略、权限拦截器等
- JwtAuthenticationFilter:从请求头解析JWT并填充SecurityContext
- TokenService:封装JWT的签发、校验、续期、刷新等逻辑
- AuthController:对外暴露登录、登出、刷新等接口
- 第三方登录客户端:以工厂+策略模式接入钉钉等第三方平台
- 领域模型:用户、身份、角色、菜单等实体及DTO/Param
章节来源
- SecurityConfig.java
- JwtAuthenticationFilter.java
- TokenService.java
- AuthController.java
- DingTalkAuthClient.java
- ThirdPartyAuthClientFactory.java
架构总览
下图展示一次典型登录请求的调用链路与数据流向,涵盖控制器、服务层、第三方登录、令牌签发与上下文填充。
sequenceDiagram
participant Client as "客户端"
participant Controller as "AuthController"
participant Service as "IAuthService"
participant UserSvc as "AuthUserServiceImpl"
participant IdentitySvc as "AuthIdentityServiceImpl"
participant Ding as "DingTalkAuthClient"
participant Token as "TokenService"
participant Filter as "JwtAuthenticationFilter"
participant SecCtx as "SecurityContext"
Client->>Controller : "POST /auth/login"
Controller->>Service : "login(LoginParam)"
alt "账号密码登录"
Service->>UserSvc : "校验用户名/密码(BCrypt)"
UserSvc-->>Service : "用户信息"
else "钉钉扫码登录"
Service->>Ding : "换取code为token"
Ding-->>Service : "第三方用户信息"
Service->>IdentitySvc : "绑定/创建本地身份"
IdentitySvc-->>Service : "本地用户映射"
end
Service->>Token : "生成JWT(含用户/角色/权限)"
Token-->>Service : "返回access_token/refresh_token"
Service-->>Controller : "登录结果"
Controller-->>Client : "200 OK + token"
Note over Client,Filter : "后续请求携带Authorization : Bearer <token>"
Client->>Filter : "带JWT的请求"
Filter->>Filter : "解析并校验签名/过期时间"
Filter->>SecCtx : "填充认证主体"
Filter-->>Client : "放行至业务处理器"
图表来源
- AuthController.java
- IAuthService.java
- AuthUserServiceImpl.java
- AuthIdentityServiceImpl.java
- DingTalkAuthClient.java
- TokenService.java
- JwtAuthenticationFilter.java
详细组件分析
SecurityConfig 安全配置
职责与要点
- 放行路径:登录、注册、验证码、第三方回调、静态资源等
- 跨域配置:允许前端域名、方法、头部、凭证
- 会话策略:无状态(STATELESS),禁用CSRF或按需关闭
- 权限拦截:基于角色的URL授权、方法级注解
- 密码编码器:使用BCryptPasswordEncoder进行密码哈希与校验
- 过滤器链:注册JwtAuthenticationFilter到SecurityFilterChain中
flowchart TD
Start(["应用启动"]) --> LoadCfg["加载SecurityConfig"]
LoadCfg --> DefineMatchers["定义匹配器与放行规则"]
DefineMatchers --> ConfigureCORS["配置跨域(CorsConfiguration)"]
ConfigureCORS --> SetSession["设置会话策略(无状态)"]
SetSession --> RegisterFilter["注册JwtAuthenticationFilter"]
RegisterFilter --> BuildChain["构建SecurityFilterChain"]
BuildChain --> Ready(["安全配置就绪"])
图表来源
- SecurityConfig.java
- CorsConfig.java
章节来源
- SecurityConfig.java
- application.yml
- CorsConfig.java
JwtAuthenticationFilter 过滤器
职责与要点
- 从请求头提取Authorization: Bearer
- 调用TokenService校验签名、过期时间、黑名单(可选)
- 将认证主体写入SecurityContext,供后续授权使用
- 对未携带或无效Token的请求直接拒绝或放行(取决于路径白名单)
flowchart TD
Enter(["进入过滤器"]) --> Extract["提取Authorization头"]
Extract --> HasToken{"是否包含Bearer Token?"}
HasToken --> |否| Next["继续过滤器链(可能由其他过滤器处理)"]
HasToken --> |是| Validate["调用TokenService校验"]
Validate --> Valid{"校验通过?"}
Valid --> |否| Reject["返回401/403"]
Valid --> |是| FillCtx["填充SecurityContext"]
FillCtx --> Next
Next --> Exit(["退出过滤器"])
图表来源
- JwtAuthenticationFilter.java
- TokenService.java
章节来源
- JwtAuthenticationFilter.java
- TokenService.java
TokenService 令牌管理
职责与要点
- 生成Access Token与Refresh Token(可分离有效期)
- 校验Token有效性(签名、过期、黑名单)
- 刷新机制:基于Refresh Token签发新Access Token
- 注销/失效:支持加入黑名单或Redis失效集合
- 载荷设计:用户ID、角色、权限、租户/部门等
classDiagram
class TokenService {
+generateAccessToken(user) string
+generateRefreshToken(user) string
+validate(token) boolean
+refresh(refreshToken) string
+invalidate(token) void
-buildPayload(user) map
-verifySignature(token) boolean
-checkExpiry(token) boolean
}
图表来源
- TokenService.java
章节来源
- TokenService.java
登录接口与认证流程
- 登录入口:AuthController暴露登录接口,接收LoginParam
- 密码校验:通过AuthUserServiceImpl调用BCrypt进行密码比对
- 第三方登录:通过DingTalkAuthClient获取第三方用户信息,再由AuthIdentityServiceImpl完成本地绑定
- 令牌签发:认证成功后由TokenService签发JWT并返回
sequenceDiagram
participant C as "客户端"
participant AC as "AuthController"
participant AS as "IAuthService"
participant U as "AuthUserServiceImpl"
participant I as "AuthIdentityServiceImpl"
participant D as "DingTalkAuthClient"
participant T as "TokenService"
C->>AC : "POST /auth/login"
AC->>AS : "login(param)"
alt "账号密码"
AS->>U : "校验密码(BCrypt)"
U-->>AS : "用户对象"
else "钉钉扫码"
AS->>D : "code -> token -> 用户信息"
D-->>AS : "第三方用户信息"
AS->>I : "绑定/创建本地身份"
I-->>AS : "本地用户映射"
end
AS->>T : "生成JWT"
T-->>AS : "返回token"
AS-->>AC : "登录成功"
AC-->>C : "200 + LoginResultDTO"
图表来源
- AuthController.java
- IAuthService.java
- AuthUserServiceImpl.java
- AuthIdentityServiceImpl.java
- DingTalkAuthClient.java
- TokenService.java
章节来源
- AuthController.java
- LoginParam.java
- LoginResultDTO.java
- UserInfoDTO.java
第三方登录集成(钉钉)
- 客户端抽象:ThirdPartyAuthClientFactory负责按类型选择具体客户端
- 钉钉实现:DingTalkAuthClient封装钉钉API交互(code换token、获取用户信息等)
- 数据映射:ThirdPartyUserInfo作为三方用户信息的统一载体
- 本地绑定:AuthIdentityServiceImpl将三方身份与本地用户关联
classDiagram
class ThirdPartyAuthClientFactory {
+getClient(type) ThirdPartyAuthClient
}
class ThirdPartyAuthClient {
<<interface>>
+exchangeCode(code) ThirdPartyUserInfo
+getUserInfo(token) ThirdPartyUserInfo
}
class DingTalkAuthClient {
+exchangeCode(code) ThirdPartyUserInfo
+getUserInfo(token) ThirdPartyUserInfo
}
class ThirdPartyUserInfo {
+string openId
+string name
+string avatar
+map~String,Object~ extra
}
ThirdPartyAuthClientFactory --> ThirdPartyAuthClient : "创建/获取"
DingTalkAuthClient ..|> ThirdPartyAuthClient
图表来源
- ThirdPartyAuthClientFactory.java
- DingTalkAuthClient.java
- ThirdPartyUserInfo.java
章节来源
- DingTalkAuthClient.java
- ThirdPartyAuthClientFactory.java
- ThirdPartyUserInfo.java
密码加密策略(BCrypt)
- 使用BCryptPasswordEncoder进行密码哈希与校验
- 登录时采用matches方法进行安全比对
- 建议定期轮换盐值与升级策略(框架默认已处理)
章节来源
- AuthUserServiceImpl.java
- AuthConstants.java
依赖关系分析
- 控制器依赖服务接口,服务实现依赖Mapper与第三方客户端
- 过滤器依赖TokenService,TokenService依赖配置与存储(如Redis)
- 安全配置集中管理放行、跨域、过滤器链顺序
graph LR
AC["AuthController"] --> IS["IAuthService"]
IS --> US["AuthUserServiceImpl"]
IS --> IDS["AuthIdentityServiceImpl"]
IDS --> DIC["DingTalkAuthClient"]
JF["JwtAuthenticationFilter"] --> TS["TokenService"]
SC["SecurityConfig"] --> JF
SC --> CC["CorsConfig"]
图表来源
- AuthController.java
- IAuthService.java
- AuthUserServiceImpl.java
- AuthIdentityServiceImpl.java
- DingTalkAuthClient.java
- JwtAuthenticationFilter.java
- TokenService.java
- SecurityConfig.java
- CorsConfig.java
章节来源
- AuthController.java
- SecurityConfig.java
性能考量
- JWT无状态特性减少会话存储压力,但需合理设置过期时间
- Refresh Token独立有效期,降低频繁重签风险
- 过滤器链尽量精简,避免重复计算
- 第三方登录调用应加超时与重试保护
- 敏感操作(如刷新)需限流与风控
[本节为通用指导,不直接分析具体文件]
故障排查指南
常见问题与定位思路
- 401未认证:检查Authorization头格式、Token是否过期、过滤器是否生效
- 403无权限:检查角色/权限配置、路径放行规则
- 登录失败:核对密码BCrypt校验、用户状态、第三方回调参数
- 跨域错误:确认CorsConfig与后端端口/域名一致
- 第三方登录异常:查看钉钉回调地址、AppKey/Secret、网络连通性
章节来源
- JwtAuthenticationFilter.java
- SecurityConfig.java
- AuthController.java
- DingTalkAuthClient.java
结论
本认证机制以Spring Security为核心,结合自定义JwtAuthenticationFilter与TokenService,实现了无状态、可扩展的JWT鉴权体系。通过统一的第三方登录抽象,系统可便捷接入多平台身份源。建议在上线前完善令牌黑名单、刷新限流、审计日志与监控告警,以提升安全性与可观测性。
[本节为总结性内容,不直接分析具体文件]
附录
- 关键实体与DTO
- AuthUser:用户主表实体
- AuthIdentity:第三方身份映射实体
- LoginParam:登录入参
- LoginResultDTO:登录响应
- UserInfoDTO:用户信息DTO
章节来源
- AuthUser.java
- AuthIdentity.java
- LoginParam.java
- LoginResultDTO.java
- UserInfoDTO.java