# 认证接口 **本文引用的文件** - [AuthController.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/AuthController.java) - [AuthService.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/AuthService.java) - [JwtAuthFilter.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/JwtAuthFilter.java) - [JwtUtils.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/JwtUtils.java) - [AuthProperties.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/AuthProperties.java) - [ApiResponse.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ApiResponse.java) - [AuthenticationException.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/AuthenticationException.java) - [ActiveSessionRegistry.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/ActiveSessionRegistry.java) - [LoginLogService.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/LoginLogService.java) ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖关系分析](#依赖关系分析) 7. [性能考虑](#性能考虑) 8. [故障排除指南](#故障排除指南) 9. [结论](#结论) 10. [附录:API 规范与调用示例](#附录api-规范与调用示例) ## 简介 本文件为 FMS 系统认证相关 RESTful API 的权威文档,覆盖用户登录、令牌校验与会话管理等能力。文档包含: - 所有认证端点的 HTTP 方法、URL、请求参数、响应格式与错误码 - JWT 认证流程的完整调用示例(登录、获取令牌、权限验证) - 认证过滤器的工作原理与拦截机制 - 常见认证错误处理与故障排除建议 ## 项目结构 认证功能主要位于后端 fms-api 模块中,关键目录与职责如下: - controller:对外暴露认证接口 - service:认证业务逻辑、会话管理、登录日志记录 - config:认证过滤器、配置属性 - utils:JWT 工具、统一响应体 - exception:认证异常类型 ```mermaid graph TB Client["客户端"] --> Filter["JwtAuthFilter
请求拦截与鉴权"] Filter --> Controller["AuthController
/auth/login"] Controller --> Service["AuthService
登录校验、生成Token、记录日志"] Service --> Db["DbUtils
查询用户信息"] Service --> Jwt["JwtUtils
签发/解析JWT"] Service --> Session["ActiveSessionRegistry
活跃会话管理"] Service --> Log["LoginLogService
登录日志记录"] Filter --> Session Filter --> Jwt ``` 图表来源 - [JwtAuthFilter.java:19-88](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/JwtAuthFilter.java#L19-L88) - [AuthController.java:19-55](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/AuthController.java#L19-L55) - [AuthService.java:19-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/AuthService.java#L19-L84) - [JwtUtils.java:18-80](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/JwtUtils.java#L18-L80) - [ActiveSessionRegistry.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/ActiveSessionRegistry.java) - [LoginLogService.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/LoginLogService.java) 章节来源 - [AuthController.java:19-55](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/AuthController.java#L19-L55) - [AuthService.java:19-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/AuthService.java#L19-L84) - [JwtAuthFilter.java:19-88](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/JwtAuthFilter.java#L19-L88) - [JwtUtils.java:18-80](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/JwtUtils.java#L18-L80) ## 核心组件 - 认证控制器:提供登录接口,接收 orgid、userid、password,返回统一响应体 - 认证服务:执行用户校验、密码比对、生成 JWT、激活会话、记录登录日志 - JWT 工具:负责密钥初始化、签发与解析令牌 - 认证过滤器:对所有非登录请求进行 Token 校验与活跃会话检查,设置上下文 - 会话注册表:维护当前活跃会话,支持单点互踢等策略 - 登录日志:记录登录成功/失败及原因 - 统一响应体:定义标准 code/message/data 结构与常用错误码 章节来源 - [AuthController.java:19-55](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/AuthController.java#L19-L55) - [AuthService.java:19-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/AuthService.java#L19-L84) - [JwtUtils.java:18-80](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/JwtUtils.java#L18-L80) - [JwtAuthFilter.java:19-88](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/JwtAuthFilter.java#L19-L88) - [ApiResponse.java:1-32](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ApiResponse.java#L1-L32) ## 架构总览 下图展示了从客户端发起登录到后续受保护接口调用的完整流程,包括过滤器拦截、JWT 校验与会话检查。 ```mermaid sequenceDiagram participant C as "客户端" participant F as "JwtAuthFilter" participant A as "AuthController" participant S as "AuthService" participant J as "JwtUtils" participant R as "ActiveSessionRegistry" participant L as "LoginLogService" C->>A : POST /auth/login {orgid, userid, password} A->>S : login(orgid, userid, password, request) S->>S : 校验用户/密码 alt 认证成功 S->>J : generateToken(userId, orgId, sessionId) S->>R : activate(orgId, userId, sessionId) S->>L : recordLogin(成功, sessionId) S-->>A : {token, orgid, user} A-->>C : ApiResponse.success(...) else 认证失败 S->>L : recordLogin(失败, 原因) S-->>A : Optional.empty() A-->>C : ApiResponse.fail(401, 错误信息) end Note over C,F : 后续受保护接口调用 C->>F : 携带 Authorization : Bearer F->>J : parseToken(token) F->>R : hasActiveSession(orgId, userId) F->>R : isActive(orgId, userId, sessionId) alt 通过 F->>F : 设置 OrgContext F-->>C : 放行至业务接口 else 未通过 F-->>C : ApiResponse.fail(401/40101, 错误信息) end ``` 图表来源 - [AuthController.java:26-55](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/AuthController.java#L26-L55) - [AuthService.java:34-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/AuthService.java#L34-L84) - [JwtUtils.java:45-66](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/JwtUtils.java#L45-L66) - [JwtAuthFilter.java:34-88](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/JwtAuthFilter.java#L34-L88) - [ActiveSessionRegistry.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/ActiveSessionRegistry.java) - [LoginLogService.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/LoginLogService.java) ## 详细组件分析 ### 认证控制器 AuthController - 路径与方法:POST /auth/login - 请求体:JSON 对象,包含 orgid、userid、password - 参数校验:orgid、userid 为空时抛出业务异常 - 成功响应:code=0,data 包含 token、orgid、user(含 id、account、name) - 失败响应:code=401,message 提示“机构码、账号或密码错误” ```mermaid flowchart TD Start(["进入 /auth/login"]) --> Parse["解析请求体
orgid, userid, password"] Parse --> Validate{"orgid/userid 是否为空?"} Validate --> |是| ThrowErr["抛出业务异常"] Validate --> |否| CallSvc["调用 AuthService.login(...)"] CallSvc --> Result{"是否返回用户信息?"} Result --> |否| FailResp["返回 401 错误"] Result --> |是| SuccessResp["返回 200 + token/orgid/user"] ThrowErr --> End(["结束"]) FailResp --> End SuccessResp --> End ``` 图表来源 - [AuthController.java:26-55](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/AuthController.java#L26-L55) 章节来源 - [AuthController.java:19-55](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/AuthController.java#L19-L55) ### 认证服务 AuthService - 登录流程: - 规范化 orgid(大写)、userid(去空白) - 查询用户并校验密码(安全比较) - 生成 JWT(包含 userId、orgId、sessionId) - 激活会话(ActiveSessionRegistry) - 记录登录日志(成功/失败) - 组装返回数据(token、orgid、user) - 密码比较:使用常量时间比较避免时序攻击 - 错误处理:账号不存在或密码错误均记录日志并返回空结果 ```mermaid flowchart TD S0["开始 login"] --> N1["规范化 orgid/userid"] N1 --> Q1["查询用户"] Q1 --> E1{"找到用户?"} E1 --> |否| L1["记录登录失败(账号不存在)"] --> R1["返回空"] E1 --> |是| P1["校验密码"] P1 --> E2{"密码正确?"} E2 --> |否| L2["记录登录失败(密码错误)"] --> R2["返回空"] E2 --> |是| T1["生成JWT(含sessionId)"] T1 --> A1["激活会话"] A1 --> L3["记录登录成功(含sessionId)"] L3 --> D1["组装返回{token, orgid, user}"] D1 --> R3["返回结果"] ``` 图表来源 - [AuthService.java:34-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/AuthService.java#L34-L84) - [AuthService.java:115-124](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/AuthService.java#L115-L124) 章节来源 - [AuthService.java:19-126](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/AuthService.java#L19-L126) ### JWT 工具 JwtUtils - 初始化:读取配置 fms.auth.jwt-secret、jwt-expiration,校验长度与有效期 - 签发:生成包含 subject(userId)、id(sessionId)、claim(orgId)、issuedAt、expiration 的 JWT - 解析:提取 userId、orgId、sessionId,缺失则抛异常 - 组织上下文:配合过滤器设置 OrgContext ```mermaid classDiagram class JwtUtils { +generateToken(userId, orgId, sessionId) String +parseToken(token) TokenClaims +getOrgId(token) String } class TokenClaims { +String userId +String orgId +String sessionId } JwtUtils --> TokenClaims : "返回" ``` 图表来源 - [JwtUtils.java:18-80](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/JwtUtils.java#L18-L80) 章节来源 - [JwtUtils.java:18-80](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/JwtUtils.java#L18-L80) - [AuthProperties.java:7-28](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/AuthProperties.java#L7-L28) ### 认证过滤器 JwtAuthFilter - 过滤范围:跳过 OPTIONS 预检与 /auth/login - 鉴权步骤: - 从 Authorization 头提取 Bearer Token - 解析 Token 获取 claims - 校验是否存在活跃会话 - 校验当前 sessionId 是否仍有效(防止多设备互踢) - 将 orgId、userId 写入上下文,放行后清理 - 失败响应:统一返回 200 状态码 + ApiResponse.fail(code, message) ```mermaid flowchart TD F0["进入 doFilterInternal"] --> H0{"是否OPTIONS或/login?"} H0 --> |是| Skip["跳过过滤"] --> Next["继续链式过滤"] H0 --> |否| G0["提取Authorization头"] G0 --> P0["解析Token"] P0 --> S0{"存在活跃会话?"} S0 --> |否| U0["返回401 未登录或失效"] S0 --> |是| I0{"sessionId仍有效?"} I0 --> |否| K0["返回40101 被其他设备顶替"] I0 --> |是| C0["设置OrgContext"] --> Next Next --> Clean["finally清理上下文"] ``` 图表来源 - [JwtAuthFilter.java:34-88](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/JwtAuthFilter.java#L34-L88) - [JwtAuthFilter.java:90-108](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/JwtAuthFilter.java#L90-L108) 章节来源 - [JwtAuthFilter.java:19-110](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/JwtAuthFilter.java#L19-L110) ### 会话管理与登录日志 - ActiveSessionRegistry:维护每个用户的活跃会话集合,支持激活、检查、有效性判断 - LoginLogService:记录登录成功/失败、原因、会话ID、请求信息等,便于审计与排查 章节来源 - [ActiveSessionRegistry.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/ActiveSessionRegistry.java) - [LoginLogService.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/LoginLogService.java) ## 依赖关系分析 - 控制器依赖服务层,服务层依赖数据库工具、JWT 工具、会话注册表与日志服务 - 过滤器依赖 JWT 工具与会话注册表,用于鉴权与上下文设置 - 配置类集中管理 JWT 密钥与过期时间 ```mermaid graph LR AC["AuthController"] --> AS["AuthService"] AS --> DBU["DbUtils"] AS --> JU["JwtUtils"] AS --> ASR["ActiveSessionRegistry"] AS --> LLS["LoginLogService"] JAF["JwtAuthFilter"] --> JU JAF --> ASR JU --> AP["AuthProperties"] ``` 图表来源 - [AuthController.java:19-55](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/AuthController.java#L19-L55) - [AuthService.java:19-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/AuthService.java#L19-L84) - [JwtAuthFilter.java:19-88](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/JwtAuthFilter.java#L19-L88) - [JwtUtils.java:18-80](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/JwtUtils.java#L18-L80) - [AuthProperties.java:7-28](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/AuthProperties.java#L7-L28) 章节来源 - [AuthController.java:19-55](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/AuthController.java#L19-L55) - [AuthService.java:19-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/AuthService.java#L19-L84) - [JwtAuthFilter.java:19-88](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/JwtAuthFilter.java#L19-L88) - [JwtUtils.java:18-80](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/JwtUtils.java#L18-L80) - [AuthProperties.java:7-28](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/AuthProperties.java#L7-L28) ## 性能考虑 - 密码比较采用常量时间比较,降低时序攻击风险 - JWT 签发与解析基于高效库实现,注意合理设置过期时间以平衡安全性与性能 - 活跃会话检查为内存级操作,适合高并发场景;如需持久化可结合缓存 - 登录日志建议异步落库,避免阻塞主流程 ## 故障排除指南 - 登录失败 - 检查 orgid、userid、password 是否正确 - 查看登录日志中的失败原因(账号不存在、密码错误) - 鉴权失败(401) - 确认 Authorization 头格式为 Bearer - 检查 Token 是否过期或被撤销 - 会话被顶替(40101) - 同一账号在其他设备登录后,旧设备会话失效,需重新登录 - 配置问题 - fms.auth.jwt-secret 长度不足 32 字节会导致启动失败 - fms.auth.jwt-expiration 必须大于 0 章节来源 - [JwtAuthFilter.java:90-108](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/JwtAuthFilter.java#L90-L108) - [JwtUtils.java:28-43](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/JwtUtils.java#L28-L43) - [ApiResponse.java:9-14](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ApiResponse.java#L9-L14) ## 结论 FMS 认证体系通过控制器、服务层、JWT 工具与过滤器协同工作,实现了安全的登录、令牌签发与会话管理。统一响应体与明确的错误码便于前端集成与排错。建议在生产环境严格配置 JWT 密钥与过期时间,并结合登录日志进行审计与监控。 ## 附录:API 规范与调用示例 ### 统一响应体 - 结构:{ code, message, data } - 常用码值: - 0:成功 - 401:未登录或凭证无效 - 40101:会话被其他设备顶替 - 1000:业务异常 - 2001:保存错误 - 500:系统错误 章节来源 - [ApiResponse.java:1-32](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ApiResponse.java#L1-L32) ### 登录接口 - 方法:POST - 路径:/auth/login - 请求体: - orgid:字符串,必填 - userid:字符串,必填 - password:字符串,必填 - 成功响应: - code=0 - data.token:JWT 字符串 - data.orgid:机构码 - data.user:{ id, account, name } - 失败响应: - code=401 - message:错误描述 章节来源 - [AuthController.java:26-55](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/AuthController.java#L26-L55) - [AuthService.java:34-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/AuthService.java#L34-L84) ### 令牌校验与会话管理 - 校验方式:在后续受保护接口的请求头中添加 Authorization: Bearer - 过滤器行为: - 解析 Token,校验签名与有效期 - 检查活跃会话是否存在且 sessionId 匹配 - 设置 OrgContext 后放行 - 失败响应: - 401:未登录或凭证无效 - 40101:账号已在其他设备登录,请重新登录 章节来源 - [JwtAuthFilter.java:34-88](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/JwtAuthFilter.java#L34-L88) - [JwtUtils.java:45-66](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/JwtUtils.java#L45-L66) ### 完整调用示例(文字版) - 登录 - 发送 POST /auth/login,请求体包含 orgid、userid、password - 成功后获取 data.token - 访问受保护接口 - 在请求头添加 Authorization: Bearer - 若返回 40101,说明会话被顶替,需重新登录 - 退出/注销 - 可通过服务端提供的注销接口或使 Token 失效(如加入黑名单)实现;当前代码未提供显式注销端点,可按需扩展 章节来源 - [AuthController.java:26-55](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/AuthController.java#L26-L55) - [JwtAuthFilter.java:34-88](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/JwtAuthFilter.java#L34-L88)