docs: add auth guide with Mermaid support

This commit is contained in:
liujing
2026-07-14 17:29:51 +08:00
parent 8c5a06b7e6
commit 66ae7980f1
14 changed files with 1585 additions and 0 deletions
+1170
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -23,6 +23,7 @@
"eslint": "^9.39.1",
"eslint-plugin-vue": "^10.6.1",
"glob": "^13.0.6",
"mermaid": "^11.16.0",
"prettier": "^3.6.2",
"sass-embedded": "^1.99.0",
"sharp": "^0.34.5",
+1
View File
@@ -85,6 +85,7 @@ export default hopeTheme(
imgSize: true, // 启用图片尺寸设置
include: true, // 启用文件包含
mark: true, // 启用标记高亮
mermaid: true, // 启用Mermaid图表
plantuml: true, // 启用PlantUML图表
spoiler: true, // 启用剧透标记
@@ -0,0 +1,11 @@
---
title: 智能巡视
index: false
icon: fa6-solid:binoculars
category:
- 工作
- 项目总结
---
<Catalog />
@@ -0,0 +1,11 @@
---
title: 算法管理平台
index: false
icon: fa6-solid:diagram-project
category:
- 工作
- 项目总结
---
<Catalog />
@@ -0,0 +1,391 @@
---
title: 平台认证与鉴权流程
icon: fa6-solid:shield-halved
date: 2026-07-14
category:
- 工作
- 项目总结
- 算法管理平台
tag:
- 认证
- 鉴权
- JWT
- 权限管理
---
本文依据当前工程中的实际实现整理,重点覆盖:
- `sunri-service-auth-spi`:认证、Token、权限和资源的 Service Bus 接口定义。
- `sunri-service-auth`:账号校验、JWT 签发、实时库会话、角色权限位和资源关系实现。
- `sunri-web-center`HTTP 登录入口、请求拦截器、`@ApiRight` 接口鉴权和菜单过滤。
本文描述的是平台现状,不把它替换成 Spring Security/RBAC 的标准实现。
<!-- more -->
## 1. 先看结论
平台的核心授权链不是“用户 -> 角色 -> 权限记录 -> 接口”这种普通关联表模型,而是:
```text
用户 -> 单个角色 -> 角色的 64 位权限位图 -> 权限位集合
|
+-> 菜单所需权限位
+-> API 所需权限位
```
登录成功后,角色的 `ROLEAUTHORITY` 位图会被拆成 `Set<Integer>`。这个权限集合会同时:
1. 返回给 Web Center
2. 写入实时库的登录会话;
3. 首次校验受保护请求时缓存在 Web Center 本地;
4. 用于过滤菜单;
5. 用于 API 请求鉴权。
## 2. 核心关系图
```mermaid
flowchart LR
U["用户<br/>userinfo"]
UG["用户组<br/>usergroup"]
R["角色<br/>userroleinfo"]
RG["角色组<br/>rolegroup"]
RB["角色权限位图<br/>ROLEAUTHORITY: Long"]
P["权限位定义<br/>cfgauthconst<br/>right + desc"]
PT["权限类型<br/>cfgauthtype"]
RES["统一权限资源<br/>cfgauthresource"]
MENU["菜单/页面/功能点<br/>type != 2"]
API["API 接口<br/>type = 2"]
RR["资源-权限位关联<br/>cfgresourceright<br/>resourceId + right"]
COMP["前端组件配置<br/>cfgcomponent"]
SESSION["实时库登录会话<br/>token / right / clientIp / TTL"]
CACHE["Web Center 本地权限缓存<br/>token -> UserAuthority"]
ACCESS["登录访问规则<br/>cfgauthaccess<br/>黑白名单/IP/MAC/时间"]
SYSCFG["认证策略配置<br/>usersysteminfo / JKSysCfg"]
U -->|"ROLESOFUSER = ROLEID<br/>当前实现为单角色"| R
U -.->|"USERGROUPID"| UG
R -->|"rolegroup"| RG
R -->|"保存"| RB
RB -->|"RightBitUtils.extract"| P
P -->|"authtypeid"| PT
PT -.->|"rolegroupid / mutex"| RG
RES --> MENU
RES --> API
MENU -->|"id = resourceId"| RR
API -->|"id = resourceId"| RR
RR -->|"right"| P
MENU -.->|"componentid = componentCode"| COMP
U -->|"登录"| SESSION
P -->|"权限集合写入 right 字段"| SESSION
SESSION -->|"checkToken 后建立"| CACHE
ACCESS -->|"登录前置校验"| U
SYSCFG -->|"密码、锁定、并发登录、待机退出"| SESSION
```
### 2.1 主干关系
| 起点 | 终点 | 实际字段/规则 | 说明 |
|---|---|---|---|
| 用户 `userinfo` | 角色 `userroleinfo` | `ROLESOFUSER = ROLEID` | 当前实现是一个用户一个角色,不是用户角色多对多。 |
| 角色 | 权限位 | `ROLEAUTHORITY` | 使用 `Long` 位图保存角色拥有的权限。 |
| 权限位定义 | 权限类型 | `cfgauthconst.authtypeid` | 权限类型用于分类、角色组适配和互斥校验。 |
| 菜单/API | 权限位 | `cfgresourceright(resourceId, right)` | 一个资源可以关联多个权限位。 |
| 菜单/API | 统一资源表 | `cfgauthresource.type` | 菜单和 API 共用一张资源表。 |
| 菜单 | 前端组件 | `componentid` | 组件配置补充菜单的组件类型和展示配置。 |
### 2.2 权限位如何保存
假设角色拥有权限位 `{0, 2, 5}`,其位图概念上是:
```text
二进制: 100101
十进制: 37
```
数据库在 `userroleinfo.ROLEAUTHORITY` 中保存合并后的 `Long`;登录时通过 `RightBitUtils.extract()` 拆成整数集合。`cfgauthconst` 保存每个权限位的名称和分类信息,而不是给每个角色保存一条关联记录。
特殊权限使用 `-1`。项目中大量管理接口使用 `@ApiRight(value = -1)`,表示需要特殊/超级权限。
## 3. 登录认证流程
浏览器登录入口是 Web Center 的 `POST /api/doLogin`Web Center 再通过 Service Bus 调用 `AuthorityVerifyService.loginVerify()`
```mermaid
sequenceDiagram
autonumber
participant F as 前端
participant WC as Web Center<br/>UserLoginController
participant LH as LoginAuthorityHandler
participant BUS as Service Bus
participant AUTH as AuthorityVerifyService
participant PIPE as LoginVerify 登录管线
participant DB as 权限数据库
participant RT as 实时库会话
participant LC as Web Center 本地缓存
F->>WC: POST /api/doLogin<br/>username + password + loginDuration
WC->>WC: 解密用户名、验证码等 Web 前置处理
WC->>LH: 执行登录处理管线
LH->>BUS: loginVerify(request)
BUS->>AUTH: AuthorityVerifyServiceImpl.loginVerify
AUTH->>PIPE: VerifyModel(LOGIN).verify
PIPE->>DB: 检查访问规则、用户、状态、密码、有效期、角色
DB-->>PIPE: ROLEAUTHORITY
PIPE->>PIPE: 拆分为 Set<Integer> rights
PIPE->>PIPE: 签发 JWT
PIPE->>RT: 写入 token、rights、clientIp、loginLimit、TTL
RT-->>AUTH: 会话写入成功
AUTH-->>LH: token + rights + expire + standbyTimes
LH->>LC: 清除旧权限缓存、建立待机心跳状态
LH-->>WC: 登录结果
WC->>WC: 使用平台安全算法加密返回 Token
WC-->>F: UserLoginVo
```
### 3.1 auth 服务登录管线
`LoginVerify` 的主处理顺序为:
```text
UniqueLoginHandler(条件启用)
-> AuthAccessLoginHandler
-> APPLoginHandler
-> BrowserLoginHandler
-> HMILoginHandler
```
浏览器登录内部还会按顺序执行多个 `BrowserLoginPipeline`,主要完成:
- 查询用户是否存在;
- 从用户角色读取权限位图并拆出权限集合;
- 检查账号状态、锁定状态、账号有效期和允许访问时间;
- 检查临时密码、普通密码、初始密码和密码有效期;
- 检查最大会话数和并发登录策略;
- 根据用户或系统配置切换 UKey、指纹等高级认证模式。
任一步设置 `errorStr` 后,后续成功逻辑不会签发有效 Token。
### 3.2 登录访问规则
`cfgauthaccess` 不属于角色权限,但属于完整认证关系:
```mermaid
flowchart LR
REQ["登录请求<br/>loginModel / IP / MAC / 时间"]
RULE["cfgauthaccess<br/>黑名单或白名单"]
INT["规则解释器"]
PASS{"允许登录?"}
NEXT["账号和密码验证"]
DENY["返回登录失败"]
REQ --> RULE --> INT --> PASS
PASS -->|是| NEXT
PASS -->|否| DENY
```
规则解释器支持日、月、星期、小时、时间段、IPv4 和 MAC 地址等条件。
## 4. 登录会话与 Token
JWT 是客户端凭证,实时库记录才是平台在线会话。会话主要包含:
| 字段 | 用途 |
|---|---|
| `username` | 当前登录用户。 |
| `token` | 当前会话 JWT。 |
| `right` | 登录时得到的权限位集合 JSON。 |
| `clientIp` | 当前来源或同源 IP 集合。 |
| `loginLimit` | 并发登录策略。 |
| `clientNum` | 同一会话下客户端数量。 |
| `interrupt` | HMI 登录中断标记。 |
| TTL | 剩余在线时间。 |
单会话通常按以下键保存:
```text
{pcname}:{paname}:token:{username}
```
允许多源同时在线时,使用 Token 的 MD5 作为会话键,并维护用户到 Token 哈希的集合:
```text
{pcname}:{paname}:token:{md5(token)}
{pcname}:{paname}:bucket:{username}
```
`expandOnlineDuration()` 只延长实时库 TTL,且不超过平台配置的最大时长;它不会重新签发 JWT。
## 5. 普通请求的 Token 校验
Web Center 使用自己的 Spring MVC 拦截器体系,不使用 Spring Security 的 `SecurityContext`
```mermaid
sequenceDiagram
autonumber
participant F as 前端
participant JI as JwtAuthenticationInterceptor
participant AS as AssembleHandle
participant JWT as Web JwtUtils
participant LC as 本地 UserAuthority 缓存
participant AUTH as Auth checkToken
participant RT as 实时库会话
participant CTRL as Controller
F->>JI: HTTP 请求 + 平台 Token
JI->>AS: 组装 ValidateObject / ReqUser
AS->>JWT: 解密并解析 JWT
JWT-->>AS: username / position / expire
AS->>LC: 按 Token 查询 UserAuthority
alt 缓存未命中
AS->>AUTH: checkToken(username, token, clientIp)
AUTH->>RT: 查询会话、TTL、权限、IP策略
RT-->>AUTH: 会话数据
AUTH-->>AS: token + rights + expire
AS->>LC: 缓存 UserAuthority
end
AS->>AS: 比较请求 Token 与缓存 Token<br/>按配置检查 IP 和过期时间
AS->>JI: Token 校验通过
JI->>CTRL: 进入接口权限校验或 Controller
```
`@PassToken` 用于无需登录的接口,例如登录和验证码。`@ApiRight(ctrl = false)` 表示接口不做权限位校验,但不等同于 `@PassToken`
## 6. API 接口鉴权
API 权限不是 `@PreAuthorize`,而是平台的 `@ApiRight`、API资源表和 Web Center 校验管线共同完成。
### 6.1 API 资源初始化
应用启动时,`DefaultAPIAuthorityManager` 扫描 Controller 方法:
1. 跳过带 `@PassToken` 的公共接口;
2. 读取请求路径、HTTP 方法和 Java 方法引用;
3. 读取 `@ApiRight` 的默认权限位和 `ctrl`
4. 通过 `AuthorityResourcesService.updateAPI()` 同步到 `cfgauthresource(type = 2)`
5.`cfgresourceright` 加载管理员配置后的最终权限位;
6. 建立“Java 方法引用 -> API 所需权限集合”的内存映射。
### 6.2 运行时校验
```mermaid
flowchart LR
REQ["已通过 Token 校验的请求"]
M["Controller Method"]
AM["APIAuthorityManager<br/>方法引用 -> 所需权限位"]
UR["用户权限集合<br/>UserAuthority.userRights"]
INTER{"权限集合有交集?"}
OK["允许访问"]
NO["拒绝并记录越权审计"]
REQ --> M --> AM --> INTER
UR --> INTER
INTER -->|是| OK
INTER -->|否| NO
```
系统支持两种执行模式:
- 缓存鉴权:`AuthorityCacheValidateHandle` 直接比较 Web Center 缓存的用户权限与 API 权限。
- 无缓存鉴权:`AuthorityRightCheckHandle` 调用 `AuthorityVerifyService.rightVerify()`,由 auth 服务比较权限。
判断逻辑是“用户权限集合”和“API 所需权限集合”存在交集即可通过,并非必须拥有接口配置的全部权限位。
## 7. 菜单鉴权
菜单和 API 使用相同的资源-权限位映射,但菜单鉴权主要决定前端资源是否可见或可用。
```mermaid
sequenceDiagram
participant F as 前端
participant WC as AuthorityResourceController
participant RH as AuthorityResourceHandler
participant AUTH as AuthorityResourcesService
participant DB as cfgauthresource + cfgresourceright
participant LC as UserAuthority 缓存
F->>WC: GET /get/user/menu
WC->>RH: getAuthMenus(username, token)
RH->>LC: 读取用户权限集合
RH->>AUTH: queryMenuTree(username)
AUTH->>DB: 查询菜单树及每个菜单所需权限
DB-->>AUTH: 菜单 + rights + ctrl + hide
AUTH-->>RH: 完整菜单树
RH->>RH: 用户权限与菜单权限求交集
RH->>RH: 根据 ctrl/hide/invalidHide 删除无权节点
RH-->>F: 用户可访问菜单树
```
需要注意:auth 服务的 `queryMenuTree()` 返回菜单及其所需权限;真正结合当前登录用户权限进行过滤的逻辑在 Web Center 的 `AuthorityResourceHandler`
## 8. 登出与权限变更
### 8.1 登出
`UserLogoutController -> LogoutHandler -> AuthorityVerifyService.loginOut()`
- 单客户端会话:删除实时库 Token 会话;
- 多客户端共享会话:减少 `clientNum`
- 多源并存会话:同时清理用户的 Token 哈希集合;
- Web Center 清除本地 `UserAuthority` 和待机心跳状态。
浏览器关闭、待机超时、管理员踢出和部分用户配置变更也会触发登出或重新登录通知。
### 8.2 权限变更何时生效
角色权限在登录时写入实时库和 Web Center 缓存,因此修改角色权限后,代码会通知受影响用户重新登录。重新登录后才会完整刷新:
```text
角色 ROLEAUTHORITY
-> 登录时拆分 rights
-> 实时库会话 right
-> Web Center UserAuthority.userRights
-> 菜单/API 鉴权
```
## 9. 容易漏掉的关系
除了“用户、角色、权限位、菜单、API”,项目中还存在以下认证相关关系:
| 关系 | 是否属于核心授权 | 作用 |
|---|---|---|
| 用户组 `usergroup` | 否 | 用户业务分类,通过 `USERGROUPID` 关联,不直接生成权限。 |
| 角色组 | 辅助 | 对角色分类,并限制可配置的权限类型。 |
| 权限类型 `cfgauthtype` | 辅助 | 对权限位分类,配置互斥关系和适用角色组。 |
| 登录访问规则 `cfgauthaccess` | 认证前置 | 按平台、IP、MAC、日期和时间执行黑白名单。 |
| 用户系统配置 | 认证策略 | 控制密码复杂度、失败锁定、账号有效期、并发登录和待机退出。 |
| 菜单组件 `cfgcomponent` | 展示辅助 | 为菜单补充前端组件类型、样式和数据配置。 |
| 实时库 Token 会话 | 核心认证 | 保存在线状态、权限快照、来源 IP 和 TTL。 |
| Web Center 权限缓存 | 核心鉴权 | 减少每个请求调用 auth 服务的次数。 |
| 双机通知 | 运行保障 | 同步 Token 检查结果、踢出状态和重新登录通知。 |
| 超级用户 | 特殊分支 | 权限来源可由配置提供,管理菜单和接口常使用权限位 `-1`。 |
| CAS/统一登录 | 特殊认证 | 通过 `genTokenFromCas()``unionLogin()` 接入平台会话体系。 |
`CfgRightMenuResource` 实体目前没有对应 Mapper 或实际调用,不能作为当前生效关系理解;实际资源与权限位关系以 `cfgresourceright` 为准。
## 10. 当前实现边界
- auth SPI 是 Service Bus 接口;面向浏览器的 REST 接口位于 Web Center。
- 平台使用自定义 MVC 拦截链,不使用 Spring Security。
- 用户当前只关联一个角色;角色权限使用 64 位位图,权限位数量受该模型限制。
- 菜单权限解决前端可见性,API 权限负责服务端访问控制;不能只配置菜单权限而不配置 API 权限。
- `checkToken()` 在多源模式优先按 Token 哈希查会话,在其他情况下会回退按用户名查会话。Web Center 随后还会比较返回 Token 和请求 Token,但直接调用 auth SPI 时应理解这一现有行为。
- 在线续期延长的是实时库会话 TTL,不是标准 OAuth2 Refresh Token 流程。
## 11. 关键代码入口
| 功能 | 代码入口 |
|---|---|
| auth SPI | `AuthorityVerifyService``AuthorityResourcesService``UserRoleService` |
| 登录实现 | `AuthorityVerifyServiceImpl.loginVerify()``LoginVerify` |
| 用户和角色权限加载 | `QueryBrowserLoginUserExistence``RightBitUtils` |
| Token 会话 | `LoginVerify.writeTokenToRedis()``AuthorityVerifyServiceImpl.checkToken()` |
| Web 登录入口 | `UserLoginController``LoginAuthorityHandler` |
| Web Token 拦截 | `JwtInterceptorConfig``AssembleHandle` |
| API 权限 | `ApiRight``DefaultAPIAuthorityManager``AuthorityCacheValidateHandle``AuthorityRightCheckHandle` |
| 菜单权限 | `AuthorityResourcesServiceImpl``MenuResourcesHandler``AuthorityResourceHandler` |