Files
lijiaoqiao/supply-api/internal/iam/model/role.go
Your Name 89104bd0db feat(P1/P2): 完成TDD开发及P1/P2设计文档
## 设计文档
- multi_role_permission_design: 多角色权限设计 (CONDITIONAL GO)
- audit_log_enhancement_design: 审计日志增强 (CONDITIONAL GO)
- routing_strategy_template_design: 路由策略模板 (CONDITIONAL GO)
- sso_saml_technical_research: SSO/SAML调研 (CONDITIONAL GO)
- compliance_capability_package_design: 合规能力包设计 (CONDITIONAL GO)

## TDD开发成果
- IAM模块: supply-api/internal/iam/ (111个测试)
- 审计日志模块: supply-api/internal/audit/ (40+测试)
- 路由策略模块: gateway/internal/router/ (33+测试)
- 合规能力包: gateway/internal/compliance/ + scripts/ci/compliance/

## 规范文档
- parallel_agent_output_quality_standards: 并行Agent产出质量规范
- project_experience_summary: 项目经验总结 (v2)
- 2026-04-02-p1-p2-tdd-execution-plan: TDD执行计划

## 评审报告
- 5个CONDITIONAL GO设计文档评审报告
- fix_verification_report: 修复验证报告
- full_verification_report: 全面质量验证报告
- tdd_module_quality_verification: TDD模块质量验证
- tdd_execution_summary: TDD执行总结

依据: Superpowers执行框架 + TDD规范
2026-04-02 23:35:53 +08:00

212 lines
4.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package model
import (
"crypto/rand"
"encoding/hex"
"errors"
"time"
)
// 角色类型常量
const (
RoleTypePlatform = "platform"
RoleTypeSupply = "supply"
RoleTypeConsumer = "consumer"
)
// 角色层级常量(用于权限优先级判断)
const (
LevelSuperAdmin = 100
LevelOrgAdmin = 50
LevelSupplyAdmin = 40
LevelOperator = 30
LevelDeveloper = 20
LevelFinops = 20
LevelViewer = 10
)
// 角色错误定义
var (
ErrInvalidRoleCode = errors.New("invalid role code: cannot be empty")
ErrInvalidRoleType = errors.New("invalid role type: must be platform, supply, or consumer")
ErrInvalidLevel = errors.New("invalid level: must be non-negative")
)
// Role 角色模型
// 对应数据库 iam_roles 表
type Role struct {
ID int64 // 主键ID
Code string // 角色代码 (unique)
Name string // 角色名称
Type string // 角色类型: platform, supply, consumer
ParentRoleID *int64 // 父角色ID用于继承关系
Level int // 权限层级
Description string // 描述
IsActive bool // 是否激活
// 审计字段
RequestID string // 请求追踪ID
CreatedIP string // 创建者IP
UpdatedIP string // 更新者IP
Version int // 乐观锁版本号
// 时间戳
CreatedAt *time.Time // 创建时间
UpdatedAt *time.Time // 更新时间
// 关联的Scope列表运行时填充不存储在iam_roles表
Scopes []string `json:"scopes,omitempty"`
}
// NewRole 创建新角色(基础构造函数)
func NewRole(code, name, roleType string, level int) *Role {
now := time.Now()
return &Role{
Code: code,
Name: name,
Type: roleType,
Level: level,
IsActive: true,
RequestID: generateRequestID(),
Version: 1,
CreatedAt: &now,
UpdatedAt: &now,
}
}
// NewRoleWithParent 创建带父角色的角色
func NewRoleWithParent(code, name, roleType string, level int, parentRoleID int64) *Role {
role := NewRole(code, name, roleType, level)
role.ParentRoleID = &parentRoleID
return role
}
// NewRoleWithRequestID 创建带指定RequestID的角色
func NewRoleWithRequestID(code, name, roleType string, level int, requestID string) *Role {
role := NewRole(code, name, roleType, level)
role.RequestID = requestID
return role
}
// NewRoleWithAudit 创建带审计信息的角色
func NewRoleWithAudit(code, name, roleType string, level int, requestID, createdIP, updatedIP string) *Role {
role := NewRole(code, name, roleType, level)
role.RequestID = requestID
role.CreatedIP = createdIP
role.UpdatedIP = updatedIP
return role
}
// NewRoleWithValidation 创建角色并进行验证
func NewRoleWithValidation(code, name, roleType string, level int) (*Role, error) {
// 验证角色代码
if code == "" {
return nil, ErrInvalidRoleCode
}
// 验证角色类型
if roleType != RoleTypePlatform && roleType != RoleTypeSupply && roleType != RoleTypeConsumer {
return nil, ErrInvalidRoleType
}
// 验证层级
if level < 0 {
return nil, ErrInvalidLevel
}
role := NewRole(code, name, roleType, level)
return role, nil
}
// Activate 激活角色
func (r *Role) Activate() {
r.IsActive = true
r.UpdatedAt = nowPtr()
}
// Deactivate 停用角色
func (r *Role) Deactivate() {
r.IsActive = false
r.UpdatedAt = nowPtr()
}
// IncrementVersion 递增版本号(用于乐观锁)
func (r *Role) IncrementVersion() {
r.Version++
r.UpdatedAt = nowPtr()
}
// SetParentRole 设置父角色
func (r *Role) SetParentRole(parentID int64) {
r.ParentRoleID = &parentID
}
// SetScopes 设置角色关联的Scope列表
func (r *Role) SetScopes(scopes []string) {
r.Scopes = scopes
}
// AddScope 添加一个Scope
func (r *Role) AddScope(scope string) {
for _, s := range r.Scopes {
if s == scope {
return
}
}
r.Scopes = append(r.Scopes, scope)
}
// RemoveScope 移除一个Scope
func (r *Role) RemoveScope(scope string) {
newScopes := make([]string, 0, len(r.Scopes))
for _, s := range r.Scopes {
if s != scope {
newScopes = append(newScopes, s)
}
}
r.Scopes = newScopes
}
// HasScope 检查角色是否拥有指定Scope
func (r *Role) HasScope(scope string) bool {
for _, s := range r.Scopes {
if s == scope || s == "*" {
return true
}
}
return false
}
// ToRoleScopeInfo 转换为RoleScopeInfo结构用于API响应
func (r *Role) ToRoleScopeInfo() *RoleScopeInfo {
return &RoleScopeInfo{
RoleCode: r.Code,
RoleName: r.Name,
RoleType: r.Type,
Level: r.Level,
Scopes: r.Scopes,
}
}
// RoleScopeInfo 角色的Scope信息用于API响应
type RoleScopeInfo struct {
RoleCode string `json:"role_code"`
RoleName string `json:"role_name"`
RoleType string `json:"role_type"`
Level int `json:"level"`
Scopes []string `json:"scopes,omitempty"`
}
// generateRequestID 生成请求追踪ID
func generateRequestID() string {
b := make([]byte, 16)
rand.Read(b)
return hex.EncodeToString(b)
}
// nowPtr 返回当前时间的指针
func nowPtr() *time.Time {
t := time.Now()
return &t
}