# permission-check Specification ## Purpose TBD - created by archiving change implement-permission-check. Update Purpose after archive. ## 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** 用于安全审计和问题排查