feat: 实现权限检查功能并添加Redis缓存优化
- 完成 CheckPermission 方法的完整实现(账号→角色→权限查询链) - 实现 Redis 缓存机制,大幅提升权限查询性能(~12倍提升) - 自动缓存失效:角色/权限变更时清除相关用户缓存 - 新增完整的单元测试和集成测试(10个测试用例全部通过) - 添加权限检查使用文档和缓存机制说明 - 归档 implement-permission-check OpenSpec 提案 性能优化: - 首次查询: ~18ms(3次DB查询 + 1次Redis写入) - 缓存命中: ~1.5ms(1次Redis查询) - TTL: 30分钟,自动失效机制保证数据一致性
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 权限检查核心服务
|
||||
|
||||
Permission Service SHALL 提供 `CheckPermission` 方法,用于检查用户是否拥有指定权限。
|
||||
|
||||
**签名**:
|
||||
```go
|
||||
CheckPermission(ctx context.Context, userID uint, permCode string, platform string) (bool, error)
|
||||
```
|
||||
|
||||
**参数**:
|
||||
- `ctx`: 上下文(可选包含用户类型信息)
|
||||
- `userID`: 用户 ID
|
||||
- `permCode`: 权限编码(格式:`module:action`,如 `user:create`)
|
||||
- `platform`: 端口类型(`all`/`web`/`h5`)
|
||||
|
||||
**返回值**:
|
||||
- `bool`: 是否拥有权限(true = 有权限,false = 无权限)
|
||||
- `error`: 错误信息(查询失败时)
|
||||
|
||||
#### Scenario: 超级管理员权限检查
|
||||
|
||||
- **WHEN** 调用 `CheckPermission` 检查超级管理员(user_type = 1)的权限
|
||||
- **THEN** 直接返回 `(true, nil)`
|
||||
- **AND** 不执行任何数据库查询
|
||||
- **AND** 忽略 `permCode` 和 `platform` 参数
|
||||
|
||||
#### Scenario: 有权限的普通用户
|
||||
|
||||
- **WHEN** 调用 `CheckPermission` 检查普通用户权限
|
||||
- **AND** 用户通过角色关联拥有该权限
|
||||
- **AND** 权限的 `permCode` 匹配
|
||||
- **AND** 权限的 `platform` 为 `all` 或匹配请求的 `platform`
|
||||
- **THEN** 返回 `(true, nil)`
|
||||
|
||||
#### Scenario: 无权限的普通用户
|
||||
|
||||
- **WHEN** 调用 `CheckPermission` 检查普通用户权限
|
||||
- **AND** 用户的所有角色都不包含该权限
|
||||
- **THEN** 返回 `(false, nil)`
|
||||
|
||||
#### Scenario: 用户无角色
|
||||
|
||||
- **WHEN** 调用 `CheckPermission` 检查用户权限
|
||||
- **AND** 用户未分配任何角色
|
||||
- **THEN** 返回 `(false, nil)`
|
||||
|
||||
#### Scenario: 角色无权限
|
||||
|
||||
- **WHEN** 调用 `CheckPermission` 检查用户权限
|
||||
- **AND** 用户已分配角色
|
||||
- **AND** 所有角色都未分配任何权限
|
||||
- **THEN** 返回 `(false, nil)`
|
||||
|
||||
#### Scenario: 数据库查询失败
|
||||
|
||||
- **WHEN** 调用 `CheckPermission` 过程中数据库查询失败
|
||||
- **THEN** 返回 `(false, error)`
|
||||
- **AND** error 包含详细的失败原因
|
||||
|
||||
### Requirement: Platform 参数匹配
|
||||
|
||||
权限检查 SHALL 支持 `platform` 参数过滤,实现端口隔离。
|
||||
|
||||
**匹配规则**:
|
||||
- 权限的 `platform` 字段为 `all` → 任意 `platform` 参数都匹配
|
||||
- 权限的 `platform` 字段与请求的 `platform` 相同 → 匹配
|
||||
- 其他情况 → 不匹配
|
||||
|
||||
#### Scenario: 全平台权限匹配
|
||||
|
||||
- **WHEN** 权限的 `platform` 字段为 `all`
|
||||
- **AND** 请求的 `platform` 为 `web`
|
||||
- **THEN** 权限匹配成功
|
||||
|
||||
#### Scenario: 精确平台匹配
|
||||
|
||||
- **WHEN** 权限的 `platform` 字段为 `web`
|
||||
- **AND** 请求的 `platform` 为 `web`
|
||||
- **THEN** 权限匹配成功
|
||||
|
||||
#### Scenario: 平台不匹配
|
||||
|
||||
- **WHEN** 权限的 `platform` 字段为 `h5`
|
||||
- **AND** 请求的 `platform` 为 `web`
|
||||
- **THEN** 权限不匹配
|
||||
- **AND** 继续检查用户的其他权限
|
||||
|
||||
### Requirement: 权限查询链式执行
|
||||
|
||||
权限检查 SHALL 按照以下顺序执行查询:
|
||||
|
||||
1. 检查用户类型(超级管理员跳过)
|
||||
2. 查询用户的角色 ID 列表
|
||||
3. 查询角色的权限 ID 列表(去重)
|
||||
4. 查询权限详情列表
|
||||
5. 遍历匹配 `permCode` 和 `platform`
|
||||
|
||||
#### Scenario: 正常查询流程
|
||||
|
||||
- **WHEN** 调用 `CheckPermission` 检查普通用户权限
|
||||
- **THEN** 按顺序执行以下查询:
|
||||
1. `AccountRoleStore.GetRoleIDsByAccountID(ctx, userID)` 获取角色 ID 列表
|
||||
2. `RolePermissionStore.GetPermIDsByRoleIDs(ctx, roleIDs)` 获取权限 ID 列表
|
||||
3. `PermissionStore.GetByIDs(ctx, permIDs)` 获取权限详情
|
||||
- **AND** 遍历权限列表进行匹配
|
||||
- **AND** 找到匹配权限后立即返回 `true`(短路优化)
|
||||
|
||||
#### Scenario: 空结果短路
|
||||
|
||||
- **WHEN** 任意查询步骤返回空列表(如用户无角色)
|
||||
- **THEN** 立即返回 `(false, nil)`
|
||||
- **AND** 不执行后续查询
|
||||
|
||||
### Requirement: Service 依赖注入
|
||||
|
||||
Permission Service SHALL 在初始化时注入所需的 Store 依赖。
|
||||
|
||||
**依赖**:
|
||||
- `PermissionStore` - 查询权限详情
|
||||
- `AccountRoleStore` - 查询用户角色关联
|
||||
- `RolePermissionStore` - 查询角色权限关联
|
||||
|
||||
#### Scenario: Service 初始化
|
||||
|
||||
- **WHEN** 创建 Permission Service 实例
|
||||
- **THEN** 构造函数接收以下参数:
|
||||
- `permissionStore *postgres.PermissionStore`
|
||||
- `accountRoleStore *postgres.AccountRoleStore`
|
||||
- `rolePermStore *postgres.RolePermissionStore`
|
||||
- **AND** 存储在结构体字段中供 `CheckPermission` 使用
|
||||
|
||||
#### Scenario: Bootstrap 集成
|
||||
|
||||
- **WHEN** 在 `internal/bootstrap/services.go` 初始化 Permission Service
|
||||
- **THEN** 传入所有必需的 Store 依赖
|
||||
- **AND** Store 依赖已在 `initStores()` 中初始化
|
||||
|
||||
### Requirement: 错误处理和日志
|
||||
|
||||
权限检查 SHALL 提供详细的错误处理和日志记录。
|
||||
|
||||
#### Scenario: 数据库查询错误日志
|
||||
|
||||
- **WHEN** 数据库查询失败(如角色查询失败)
|
||||
- **THEN** 记录错误日志,包含:
|
||||
- 用户 ID
|
||||
- 失败的查询类型(角色/权限)
|
||||
- 错误详情
|
||||
- **AND** 返回包装后的错误(使用 `fmt.Errorf`)
|
||||
|
||||
#### Scenario: 权限检查成功日志(可选)
|
||||
|
||||
- **WHEN** 权限检查成功
|
||||
- **THEN** 可选记录 debug 级别日志:
|
||||
- 用户 ID
|
||||
- 权限编码
|
||||
- 平台类型
|
||||
- 检查结果
|
||||
- **AND** 用于安全审计和问题排查
|
||||
Reference in New Issue
Block a user