Auth 是 Bacon 的统一认证与会话业务域。
本文档定义 Auth 模块的需求边界、实现约束和稳定契约。
本文档用于指导设计、实现和测试。
- 账号密码登录
- 手机短信登录
- 企业微信扫码登录
- 微信登录
GitHub OAuth2登录- 向第三方应用提供
OAuth2授权服务 - 访问令牌签发
- 刷新令牌签发
- 刷新令牌换发
- 登出
- 当前会话查询
- 当前用户本人修改密码
- 首次登录强制改密校验
- 密码过期校验
- 多因子认证登录编排
- 凭据锁定校验
- 登录失败处理
- 会话校验
- 会话失效
- 认证审计日志
- 用户主数据维护
UserIdentity主数据维护- 管理员初始化密码
- 管理员重置密码
- 管理员修改他人密码
- 角色、菜单、资源、数据权限维护
- SSO
OpenID Connect Discovery- 动态
OAuthClient注册 - 除
GitHub OAuth2、微信登录、企业微信扫码外的其他社交登录 - C 端账号体系
Auth负责登录、令牌签发、令牌刷新、登出、会话校验和认证流程Auth负责用户本人修改密码Auth负责多因子认证流程编排Auth负责凭据失败后的锁定写回编排Auth负责向第三方应用提供标准OAuth2授权能力Auth负责认证审计日志Auth不拥有User、UserIdentity、Tenant、Role、Menu、Resource主数据Auth不拥有权限主数据Auth不直接维护管理员密码管理能力
UPMS负责User、UserIdentity、UserCredential、Tenant、Department、Post、Role、Menu、ResourceUPMS负责授权关系、数据权限、只读查询能力UPMS负责密码数据、凭据状态、多因子因子配置和凭据锁定主数据UPMS负责管理员初始化密码、重置密码、修改密码UPMS负责用户状态、租户状态、授权结果和数据权限结果
Gateway负责接收客户端请求并执行统一认证拦截Gateway不拥有认证主数据Gateway不持久化会话Gateway只消费Auth提供的认证结果或令牌校验结果
- 第三方应用是
Auth的授权客户端 - 第三方应用通过
OAuth2 client身份接入Auth - 第三方应用固定为服务端应用
- 第三方应用不直接访问
UPMS主数据 - 第三方应用只能消费
Auth签发的授权码、访问令牌和用户授权结果
Auth只能依赖bacon-upms-apiAuth不得依赖UPMS内部实现Auth不得在token payload中保存权限数据Auth认证成功后必须通过UserIdentity定位唯一UserAuth读取User、UserIdentity、UserCredential、Tenant状态时,只能通过UserReadFacadeAuth写回凭据失败次数和锁定清零时,只能通过UserCredentialCommandFacadeAuth认证成功后如需权限数据,只能通过PermissionReadFacade读取UPMS触发的用户停用、用户删除、管理员初始化密码、管理员重置密码、管理员修改密码、租户停用,必须通过Auth暴露的会话失效契约触发即时失效- 单体模式使用本地
Facade实现 - 微服务模式使用远程
Facade实现,并保持同一契约
- 跨域
Facade DTO- 对外共享枚举
固定接口:
TokenVerifyFacadeSessionCommandFacadeOAuthClientReadFacade
TokenVerifyFacade 固定方法:
verifyAccessToken(accessToken),返回固定SessionValidationResponsegetSessionContext(sessionId),返回固定CurrentSessionResponse
verifyAccessToken 返回值至少包含:
validuserIdtenantIdsessionIdidentityIdidentityType
getSessionContext 返回值至少包含:
sessionIduserIdtenantIdsessionStatuslastAccessTime
SessionCommandFacade 固定方法:
invalidateUserSessions(tenantId, userId, reason)invalidateTenantSessions(tenantId, reason)invalidateSession(sessionId, reason)
OAuthClientReadFacade 固定方法:
getClientByClientId(clientId),返回固定OAuthClientDTO
getClientByClientId 返回值至少包含:
clientIdclientNamegrantTypesscopesredirectUrisenabled
SessionCommandFacade 使用方固定为:
UPMSGateway- 其他经架构评审确认需要执行认证态即时失效的业务域
Controller- 请求
DTO - 响应
VO Assembler- 对外适配端点
固定端点:
POST /auth/login/passwordPOST /auth/login/smsPOST /auth/login/wecomGET /auth/login/github/callbackGET /oauth2/authorizePOST /oauth2/authorize/decisionPOST /oauth2/tokenPOST /oauth2/introspectPOST /oauth2/revokeGET /oauth2/userinfoPOST /auth/token/refreshPOST /auth/logoutPOST /auth/password/changeGET /auth/session/current
固定服务:
LoginApplicationServiceTokenApplicationServicePasswordApplicationServiceSessionApplicationServiceOAuth2AuthorizationApplicationServiceOAuth2ClientApplicationServiceAuthAuditApplicationService
- 聚合、实体、值对象
- 领域服务
Repository接口- 领域规则和不变量
- 令牌签发实现
- 会话存储实现
- 缓存实现
- 第三方登录适配器
- 短信验证码发送与校验适配器
- 审计日志持久化
Auth独立启动模块- 微服务模式运行入口
- 装配
bacon-auth-*与公共基础模块
AuthSessionAccessTokenClaimsRefreshTokenSessionOAuthClientOAuthAuthorizationCodeOAuthAccessTokenOAuthRefreshTokenOAuthConsentLoginRequestLoginResultAuthPrincipalSmsCaptchaThirdPartyIdentityBindingAuthAuditLog
identityType固定为ACCOUNT、EMAIL、PHONE、GITHUB、WECHAT、WECOMloginType固定为PASSWORD、SMS、WECHAT、WECOM、GITHUBsecondFactorType固定为TOTPsessionStatus固定为ACTIVE、LOGGED_OUT、INVALIDATED、EXPIRED- 用户登录态
tokenStatus固定为ACTIVE、USED、INVALIDATED、EXPIRED - 第三方
OAuth2 tokenStatus固定为ACTIVE、USED、REVOKED、EXPIRED decision固定为APPROVE、REJECTOAuthClient.clientType固定为CONFIDENTIAL
- 未特别说明时,
access token和refresh token指用户登录态令牌 - 面向第三方应用的令牌统一写作
OAuth2 access token和OAuth2 refresh token token payload仅指用户登录态JWT claimsauthorization code仅指第三方应用OAuth2授权码session仅指用户登录会话,不指第三方应用授权码或第三方令牌tenantId固定承载TenantId文本值userId在Auth中固定承载UserId文本值
UserLoginResponse至少包含accessToken、refreshToken、tokenType、expiresIn、sessionId、userId、tenantIdUserLoginResponse.needChangePassword只在账号密码登录场景返回UserTokenRefreshResponse至少包含accessToken、refreshToken、tokenType、expiresIn、sessionIdOAuthClientDTO至少包含clientId、clientName、grantTypes、scopes、redirectUris、enabledOAuth2TokenResponse至少包含access_token、token_type、expires_in、refresh_token、scopeOAuth2IntrospectionResponse至少包含active、client_id、scope、sub、tenant_id、expOAuth2UserinfoResponse至少包含sub、tenant_idOAuth2UserinfoResponse.name只在授予profile时返回SessionValidationResponse至少包含valid、tenantId、userId、sessionId、identityType、expireAtCurrentSessionResponse至少包含sessionId、tenantId、userId、identityType、loginType、sessionStatus、issuedAt、lastAccessTime、expireAt
AuthSession至少包含id、sessionId、tenantId、userId、identityId、identityType、sessionStatus、loginType、issuedAt、lastAccessTime、expireAt、logoutAt、invalidateReasonAccessTokenClaims至少包含sub、sessionId、tenantId、userId、identityId、identityType、iat、exp、issRefreshTokenSession至少包含sessionId、refreshTokenHash、tokenStatus、issuedAt、expireAt、usedAtOAuthClient至少包含id、clientId、clientSecret、clientName、clientType、grantTypes、scopes、redirectUris、accessTokenTtlSeconds、refreshTokenTtlSeconds、enabled、contact、remark、createdAt、updatedAtOAuthAuthorizationCode至少包含authorizationCode、clientId、tenantId、userId、redirectUri、scopes、codeChallenge、codeChallengeMethod、issuedAt、expireAt、usedOAuthAccessToken至少包含tokenId、tokenHash、clientId、tenantId、userId、scopes、issuedAt、expireAt、tokenStatusOAuthRefreshToken至少包含tokenId、tokenHash、accessTokenId、clientId、tenantId、userId、issuedAt、expireAt、tokenStatusOAuthConsent至少包含clientId、tenantId、userId、grantedScopes、grantedAtAuthAuditLog至少包含id、tenantId、userId、identityId、identityType、sessionId、clientId、actionType、resultStatus、failureReason、requestIp、userAgent、occurredAt
-
AuthSession.sessionId全局唯一 -
RefreshTokenSession.refreshTokenHash全局唯一 -
OAuthClient.clientId全局唯一 -
OAuthAuthorizationCode.authorizationCode全局唯一 -
OAuthAccessToken.tokenId全局唯一 -
OAuthAccessToken.tokenHash全局唯一 -
OAuthRefreshToken.tokenId全局唯一 -
OAuthRefreshToken.tokenHash全局唯一 -
AuthSession必须建立(tenantId, userId, sessionStatus)索引 -
RefreshTokenSession必须建立(sessionId, tokenStatus)索引 -
OAuthAuthorizationCode必须建立(clientId, userId, expireAt)索引 -
OAuthAccessToken必须建立(clientId, userId, tokenStatus)索引 -
AuthAuditLog必须建立(tenantId, occurredAt)、(userId, occurredAt)、(clientId, occurredAt)索引
Tenant是一级隔离边界AuthSession必须带tenantIdAuthSession必须带userIdAuthSession必须带identityIdAuthSession必须带identityTypeAuth只接受来自已启用Tenant的登录Auth只接受来自已启用User的登录Auth只接受来自已启用UserIdentity的登录- 同一认证请求必须定位唯一
User
- 登录方式固定为:账号密码、手机短信、企业微信扫码、
GitHub OAuth2 - 不同登录方式最终必须映射到同一
User - 不同登录方式共享同一会话模型
- 禁用某个
UserIdentity只影响该登录方式,不等于禁用User
- 用户登录成功后必须同时签发用户登录态
access token和用户登录态refresh token access token固定为签名JWTrefresh token固定为高强度随机字符串- 用户登录态
access token TTL固定为1800秒 - 用户登录态
refresh token TTL固定为604800秒 access token与refresh token必须绑定同一sessionIdtoken payload只保存身份信息和会话定位信息,不保存权限数据token payload至少包含userId、tenantId、sessionId、identityId、identityType、issuedAt、expireAtJWT iss固定为bacon-authrefresh token不得明文落日志- 同一
refresh token只能成功使用一次 - 刷新令牌换发后,旧
refresh token立即失效
Auth必须作为标准OAuth2 Authorization Server向第三方应用提供授权服务- 第三方应用接入主体固定为
OAuthClient - 第三方应用固定为服务端
CONFIDENTIALclient,不支持浏览器纯前端PUBLICclient OAuthClient.clientId全局唯一OAuthClient.clientType固定为CONFIDENTIALOAuthClient状态字段统一使用enabledclientSecret不得明文落日志clientSecret固定使用强哈希存储,不明文存储OAuth2授权范围固定由scope表达scope必须使用稳定英文标识- 固定支持
authorization_code、refresh_token - 不支持
implicit - 不支持动态
OAuthClient注册 - 不支持
client_credentials authorization code TTL固定为300秒OAuth2 access token TTL默认固定为1800秒OAuth2 refresh token TTL默认固定为2592000秒- 第三方应用授权流程固定要求
PKCE code_challenge_method固定支持S256OAuth2 refresh token固定为一次性使用OAuth2 refresh token成功换发后,旧OAuth2 refresh token立即失效- 授权码必须一次性使用
- 授权码必须绑定
clientId、userId、tenantId、redirectUri、scopes - 未注册的
redirectUri必须拒绝授权 - 已停用
OAuthClient不得发起授权和换发令牌 - 第三方应用访问令牌校验必须支持令牌有效性查询
- 第三方应用令牌撤销后必须立即失效
- 提供
userinfo能力,但不提供完整OpenID Connect Discovery - 不签发
id_token
scope固定支持openid、profileopenid只表示第三方应用可读取稳定用户主体标识profile表示第三方应用可读取允许暴露的基础身份信息- 未授予
openid时,不得访问GET /oauth2/userinfo - 未授予
profile时,不得返回name - 当前
userinfo最多返回sub、tenant_id、name userinfo.sub固定映射为User.iduserinfo.tenant_id固定映射为当前用户所属tenantId
GET /oauth2/authorize成功校验后,必须生成服务端授权请求上下文- 授权请求上下文固定使用
authorizationRequestId标识 authorizationRequestId全局唯一- 授权请求上下文必须绑定
clientId、redirectUri、scope、state、codeChallenge、codeChallengeMethod、tenantId、userId - 授权请求上下文
TTL固定为300秒 POST /oauth2/authorize/decision必须基于authorizationRequestId提交授权决定POST /oauth2/authorize/decision不得直接信任前端重复提交的redirectUri、codeChallenge、codeChallengeMethod- 授权请求上下文只可使用一次
- 授权请求上下文过期或已使用时,授权确认必须失败
- 每次成功登录必须创建新的
AuthSession - 单用户并发会话数不设固定上限
AuthSession必须记录创建时间、最后访问时间、失效原因AuthSession必须支持按tenantId、userId、sessionId查询- 会话校验必须同时校验令牌签名、过期时间和服务端会话状态
- 用户显式登出后,当前会话立即失效
- 用户停用后,全部活动会话立即失效
- 用户删除后,全部活动会话立即失效
- 管理员初始化密码、重置密码、修改密码后,全部活动会话立即失效
Tenant停用后,该租户下全部活动会话立即失效- 会话失效后,用户必须重新登录
- 用户本人修改密码归
Auth Auth不保存密码主数据- 用户本人修改密码时必须先校验旧密码
- 新密码规则必须与
UPMS保持一致 - 密码长度至少
8位 - 密码必须同时包含大写字母、小写字母、数字
- 密码可以包含特殊字符
- 新密码不得与旧密码相同
Auth不得记录明文密码、哈希值、临时密码到日志、审计日志、消息体、缓存- 用户本人修改密码成功后,当前和其他活动会话立即失效
- 用户本人修改密码后,用户必须重新登录
Auth登录成功后必须从UPMS查询用户状态、菜单树、权限码和数据权限上下文Auth不拥有权限计算规则Auth不缓存权限主数据Auth如缓存登录态附属信息,必须与会话生命周期保持一致- 登录成功响应必须包含会话建立结果
- 登录成功响应不得直接返回菜单树、权限码、数据权限上下文
- 前端登录成功后,如需菜单树、权限码、数据权限上下文,必须调用
UPMS的只读查询接口获取
- 认证失败必须返回统一失败结果
- 不存在的账号、错误密码、无效短信验证码、无效第三方回调码、用户停用、租户停用必须视为认证失败
- 认证失败不得泄露用户是否存在、密码是否正确、手机号是否已注册等敏感判断细节
- 认证失败必须记录审计日志
- 刷新令牌无效、已使用、已过期、会话已失效时必须拒绝换发
OAuth2错误返回必须使用标准错误码语义- 固定错误码至少包括
invalid_request、invalid_client、invalid_grant、unauthorized_client、invalid_scope、access_denied
- 使用
account + password发起登录 - 通过
UserIdentity(ACCOUNT)定位唯一User - 校验密码
- 校验
Tenant、User、UserIdentity状态 - 创建
AuthSession - 返回令牌和当前用户基础认证信息
补充约束:
account不区分登录入口来源- 请求体固定包含
account、password - 返回结果不得包含密码相关数据
- 成功响应固定使用
UserLoginResponse
- 使用
phone + smsCaptcha发起登录 - 通过
UserIdentity(PHONE)定位唯一User - 校验短信验证码
- 校验
Tenant、User、UserIdentity状态 - 创建
AuthSession - 返回令牌和当前用户基础认证信息
补充约束:
- 短信验证码必须一次性使用
- 短信验证码校验成功后立即失效
- 请求体固定包含
phone、smsCaptcha - 成功响应固定使用
UserLoginResponse
- 通过企业微信扫码回调完成登录
- 通过企业微信身份标识定位
UserIdentity(WECOM) - 校验
Tenant、User、UserIdentity状态 - 创建
AuthSession - 返回令牌和当前用户基础认证信息
补充约束:
- 无有效绑定关系时登录必须失败
- 第三方临时授权码只能使用一次
- 成功响应固定使用
UserLoginResponse
- 通过
GitHub OAuth2授权码回调完成登录 - 通过
GitHub身份标识定位UserIdentity(GITHUB) - 校验
Tenant、User、UserIdentity状态 - 创建
AuthSession - 返回令牌和当前用户基础认证信息
补充约束:
- 无有效绑定关系时登录必须失败
- 不支持首次登录自动注册
- 成功响应固定使用
UserLoginResponse
- 使用用户登录态
refresh token换发新的用户登录态access token和用户登录态refresh token - 校验当前会话状态
- 校验
refresh token是否属于当前会话 - 换发成功后返回新的令牌对
补充约束:
- 刷新操作必须幂等失败,不得重复成功
- 刷新成功后旧
refresh token立即失效 - 请求体固定包含
refreshToken - 成功响应固定使用
UserTokenRefreshResponse
- 向第三方应用提供
OAuth2授权服务 - 支持第三方应用发起授权请求
- 支持用户完成授权确认
- 支持使用授权码换取访问令牌
- 支持访问令牌校验
- 支持访问令牌撤销
补充约束:
- 固定支持
authorization_code和refresh_token - 授权确认结果必须绑定当前登录用户
- 授权码、访问令牌、刷新令牌必须绑定
clientId - 授权范围不得超出
OAuthClient已注册范围 GET /oauth2/authorize固定请求参数包含response_type=code、client_id、redirect_uri、scope、state、code_challenge、code_challenge_methodGET /oauth2/authorize负责登录态检查、客户端校验、授权页展示上下文生成GET /oauth2/authorize成功响应至少包含authorizationRequestId、clientId、clientName、scope、statePOST /oauth2/authorize/decision固定请求参数包含authorizationRequestId、decisiondecision固定值为APPROVE、REJECTPOST /oauth2/token固定支持grant_type=authorization_code和grant_type=refresh_tokenauthorization_code换令牌请求固定包含grant_type、code、redirect_uri、client_id、client_secret、code_verifierrefresh_token换令牌请求固定包含grant_type、refresh_token、client_id、client_secretPOST /oauth2/introspect固定请求参数包含token、client_id、client_secretPOST /oauth2/revoke固定请求参数包含token、client_id、client_secretGET /oauth2/userinfo固定使用OAuth2 access token读取当前授权用户信息- 授权码换令牌成功响应固定使用
OAuth2TokenResponse - 令牌校验成功响应固定使用
OAuth2IntrospectionResponse - 用户信息读取成功响应固定使用
OAuth2UserinfoResponse - 用户拒绝授权时,必须返回标准
access_denied错误 OAuth2 refresh_token换发成功后,旧OAuth2 refresh_token不得再次使用
- 维护第三方应用接入信息
- 维护
clientId、clientSecret、名称、授权范围、回调地址、状态 - 为授权服务提供只读查询能力
补充约束:
OAuthClient维护归属固定为AuthclientId全局唯一clientSecret必须加密存储或哈希存储redirectUris必须逐项完整登记- 已停用
OAuthClient不得参与授权流程 - 受保护资源范围固定为认证用户身份信息读取
OAuthClient必须支持维护联系人、备注、创建时间、更新时间
- 登录成功后不直接返回菜单树、权限码、数据权限上下文
Auth仅负责在认证阶段拉取并校验授权相关结果- 前端如需页面导航与按钮权限,必须通过
UPMS的只读接口读取
补充约束:
Auth不新增菜单树查询接口Auth不新增权限码查询接口Auth不新增数据权限上下文查询接口Auth不作为权限结果缓存的唯一来源
- 用户可主动登出当前会话
- 登出后当前
AuthSession状态改为LOGGED_OUT - 登出后当前
access token和refresh token均不得再使用
补充约束:
- 请求头必须携带当前
access token - 重复登出不得产生脏数据
- 登出操作必须记录审计日志
- 当前登录用户可修改本人密码
- 必须校验旧密码
- 必须校验新密码复杂度
- 修改成功后失效全部活动会话
补充约束:
- 不允许绕过旧密码校验
- 请求体固定包含
oldPassword、newPassword - 修改密码成功必须记录审计日志
Auth必须提供令牌校验能力- 校验成功后返回稳定的会话上下文
- 校验失败时返回明确的失败状态
补充约束:
- 校验结果必须可被
Gateway和其他服务复用 - 校验逻辑不得依赖权限数据
- 成功响应固定使用
SessionValidationResponse
- 返回当前登录用户的基础会话信息
- 返回当前会话状态、登录方式、登录时间、最近访问时间
补充约束:
- 不返回密码、刷新令牌、第三方敏感凭据
- 成功响应固定使用
CurrentSessionResponse
- 记录登录成功
- 记录登录失败
- 记录第三方应用授权成功和失败
- 记录令牌校验和撤销
- 记录刷新令牌成功和失败
- 记录登出
- 记录本人修改密码
- 记录会话批量失效
必须记录的字段:
tenantIduserIdidentityIdidentityTypesessionId- 操作时间
- 操作类型
- 请求来源
- 客户端
ip userAgentclientId- 结果状态
- 失败原因摘要
补充约束:
- 审计日志必须持久化存储
- 审计日志必须可按
tenantId、userId、identityType、操作类型、结果状态、时间范围查询 - 审计日志不得记录明文密码、哈希值、短信验证码、用户登录态
refresh token、OAuth2 access token、OAuth2 refresh token - 审计日志写入失败不得影响主业务提交结果
缓存命名约定:
auth:session:*、auth:refresh-token:*、auth:user-sessions:*、auth:tenant-sessions:*只用于用户登录态auth:oauth-*只用于第三方应用OAuth2授权能力
缓存键:
auth:session:{sessionId}auth:refresh-token:{refreshTokenHash}auth:user-sessions:{tenantId}:{userId}auth:tenant-sessions:{tenantId}auth:oauth-client:{clientId}auth:oauth-code:{authorizationCode}auth:oauth-access-token:{accessTokenId}auth:oauth-refresh-token:{refreshTokenId}
缓存内容:
- 会话缓存保存
AuthSession核心状态 - 刷新令牌缓存保存
refresh token哈希、会话绑定关系、过期时间和使用状态 - 用户会话索引缓存保存用户活动
sessionId集合 - 租户会话索引缓存保存租户活动
sessionId集合 OAuthClient缓存保存客户端接入配置- 授权码缓存保存授权码绑定关系和过期时间
OAuth2 access token缓存保存令牌状态、客户端绑定关系、用户绑定关系和过期时间OAuth2 refresh token缓存保存令牌状态、客户端绑定关系、用户绑定关系和过期时间- 授权请求上下文缓存保存
authorizationRequestId对应的授权上下文和使用状态
缓存时长:
auth:session:{sessionId}的TTL固定与会话剩余有效期一致auth:refresh-token:{refreshTokenHash}的TTL固定为对应refresh token剩余有效期auth:oauth-client:{clientId}的TTL固定为3600秒auth:oauth-code:{authorizationCode}的TTL固定为300秒auth:oauth-access-token:{accessTokenId}的TTL固定与对应第三方访问令牌剩余有效期一致auth:oauth-refresh-token:{refreshTokenId}的TTL固定与对应第三方刷新令牌剩余有效期一致- 授权请求上下文缓存
TTL固定为300秒
失效触发:
- 登录成功且旧同端策略要求替换会话时
- 用户主动登出
- 刷新令牌换发
- 用户本人修改密码
- 管理员初始化密码
- 管理员重置密码
- 管理员修改密码
- 用户停用
- 用户删除
- 租户停用
- 会话自然过期
OAuthClient配置变更OAuthClient停用- 授权码兑换成功
- 第三方访问令牌撤销
- 第三方刷新令牌换发
- 第三方刷新令牌撤销
- 授权请求上下文使用完成
- 授权请求上下文超时过期
补充约束:
- 缓存以主动失效为主,
TTL为兜底 refresh token只保存哈希值,不保存明文- 会话缓存和刷新令牌缓存不得混合存储
- 第三方访问令牌缓存不得与用户登录会话缓存混合存储
- 第三方刷新令牌缓存不得与用户登录刷新令牌缓存混合存储
- 影响会话有效性的变更必须主动失效相关缓存
- 客户端提交
account + password Auth通过UserIdentity(ACCOUNT)定位唯一UserAuth校验密码和状态Auth创建AuthSessionAuth从UPMS读取菜单树、权限码和数据权限上下文Auth签发access token和refresh token- 客户端携带
access token访问受保护资源
- 客户端提交
refresh token Auth校验refresh token、会话状态和过期时间Auth使旧refresh token失效Auth换发新的令牌对- 客户端使用新的令牌继续访问
- 客户端发起登出
Auth定位当前sessionIdAuth将当前会话置为LOGGED_OUTAuth失效会话和刷新令牌缓存- 用户后续访问受保护资源时认证失败
- 第三方应用携带
clientId、redirectUri、scope发起授权请求 Auth校验OAuthClient状态和redirectUriAuth生成authorizationRequestId并保存授权请求上下文- 用户完成登录并确认授权
Auth通过POST /oauth2/authorize/decision基于authorizationRequestId接收授权确认结果Auth生成一次性授权码- 第三方应用使用授权码换取访问令牌和刷新令牌
- 第三方应用后续使用访问令牌访问受保护接口
- 第三方应用携带
token、clientId、clientSecret发起令牌校验或撤销 Auth校验OAuthClient身份与状态Auth校验目标令牌状态、归属和过期时间Auth返回令牌有效性结果或执行撤销- 撤销后的令牌后续不得继续使用
- 用户登录成功
- 前端调用
UPMS菜单树、权限码、数据权限上下文只读接口 UPMS根据tenantId、userId返回最新授权结果- 前端按返回结果渲染导航和按钮权限
- 第三方应用携带第三方访问令牌访问
GET /oauth2/userinfo Auth校验令牌状态、归属、过期时间和授权范围Auth按已授予scope返回允许暴露的用户身份信息
- 当前登录用户提交旧密码和新密码
Auth校验旧密码和新密码规则Auth调用UPMS完成密码持久化更新Auth失效该用户全部活动会话- 用户后续访问受保护资源时认证失败
- 用户必须重新登录
UPMS或上游管理动作触发用户停用、用户删除、管理员改密或租户停用UPMS通过SessionCommandFacade调用Auth失效契约Auth批量失效相关活动会话和刷新令牌- 受影响用户后续访问受保护资源时认证失败
- 未删除用户如状态恢复,必须重新登录
| ID | Category | Requirement |
|---|---|---|
| NFR-001 | Security | 所有认证接口必须使用统一安全基线并防止敏感信息泄露 |
| NFR-002 | Security | token payload 不得包含权限数据和密码相关数据 |
| NFR-003 | Consistency | 会话失效后,后续认证请求必须立即感知失效结果 |
| NFR-004 | Performance | 高频会话校验必须优先走缓存 |
| NFR-005 | Availability | 认证流程不能成为登录瓶颈 |
| NFR-006 | Architecture | 必须同时支持单体和微服务装配 |
| NFR-007 | Maintainability | 实现必须严格遵守 interfaces -> application -> domain -> infra 分层 |
| NFR-008 | Compatibility | Facade + DTO 契约必须同时支持本地和远程实现 |
| NFR-009 | Auditability | 认证审计日志必须持久化、可检索、可追溯 |
| NFR-010 | Cache Consistency | 影响会话有效性的变更必须主动失效相关缓存 |
| NFR-011 | Password Security | 明文密码、短信验证码、刷新令牌不得进入日志、审计日志、消息体和缓存明文 |
| NFR-012 | OAuth2 Compatibility | 对第三方应用的授权服务必须遵循标准 OAuth2 语义 |
| NFR-013 | DTO Stability | 登录、会话校验、OAuth2 令牌相关 DTO/VO 字段必须保持向后兼容 |
| NFR-014 | Observability | 登录、发令牌、撤销、失效链路必须具备可追踪日志和审计记录 |