## 设计文档 - 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规范
173 lines
4.4 KiB
Go
173 lines
4.4 KiB
Go
package model
|
||
|
||
import (
|
||
"time"
|
||
)
|
||
|
||
// UserRoleMapping 用户-角色关联模型
|
||
// 对应数据库 iam_user_roles 表
|
||
type UserRoleMapping struct {
|
||
ID int64 // 主键ID
|
||
UserID int64 // 用户ID
|
||
RoleID int64 // 角色ID (FK -> iam_roles.id)
|
||
TenantID int64 // 租户范围(NULL表示全局,0也代表全局)
|
||
GrantedBy int64 // 授权人ID
|
||
ExpiresAt *time.Time // 角色过期时间(nil表示永不过期)
|
||
IsActive bool // 是否激活
|
||
|
||
// 审计字段
|
||
RequestID string // 请求追踪ID
|
||
CreatedIP string // 创建者IP
|
||
UpdatedIP string // 更新者IP
|
||
Version int // 乐观锁版本号
|
||
|
||
// 时间戳
|
||
CreatedAt *time.Time // 创建时间
|
||
UpdatedAt *time.Time // 更新时间
|
||
GrantedAt *time.Time // 授权时间
|
||
}
|
||
|
||
// NewUserRoleMapping 创建新的用户-角色映射
|
||
func NewUserRoleMapping(userID, roleID, tenantID int64) *UserRoleMapping {
|
||
now := time.Now()
|
||
return &UserRoleMapping{
|
||
UserID: userID,
|
||
RoleID: roleID,
|
||
TenantID: tenantID,
|
||
IsActive: true,
|
||
RequestID: generateRequestID(),
|
||
Version: 1,
|
||
CreatedAt: &now,
|
||
UpdatedAt: &now,
|
||
}
|
||
}
|
||
|
||
// NewUserRoleMappingWithGrant 创建带授权信息的用户-角色映射
|
||
func NewUserRoleMappingWithGrant(userID, roleID, tenantID, grantedBy int64, expiresAt *time.Time) *UserRoleMapping {
|
||
now := time.Now()
|
||
return &UserRoleMapping{
|
||
UserID: userID,
|
||
RoleID: roleID,
|
||
TenantID: tenantID,
|
||
GrantedBy: grantedBy,
|
||
ExpiresAt: expiresAt,
|
||
GrantedAt: &now,
|
||
IsActive: true,
|
||
RequestID: generateRequestID(),
|
||
Version: 1,
|
||
CreatedAt: &now,
|
||
UpdatedAt: &now,
|
||
}
|
||
}
|
||
|
||
// HasRole 检查用户是否拥有指定角色
|
||
func (m *UserRoleMapping) HasRole(roleID int64) bool {
|
||
return m.RoleID == roleID && m.IsActive
|
||
}
|
||
|
||
// IsGlobalRole 检查是否为全局角色(租户ID为0或nil)
|
||
func (m *UserRoleMapping) IsGlobalRole() bool {
|
||
return m.TenantID == 0
|
||
}
|
||
|
||
// IsExpired 检查角色是否已过期
|
||
func (m *UserRoleMapping) IsExpired() bool {
|
||
if m.ExpiresAt == nil {
|
||
return false // 永不过期
|
||
}
|
||
return time.Now().After(*m.ExpiresAt)
|
||
}
|
||
|
||
// IsValid 检查角色分配是否有效(激活且未过期)
|
||
func (m *UserRoleMapping) IsValid() bool {
|
||
return m.IsActive && !m.IsExpired()
|
||
}
|
||
|
||
// Revoke 撤销角色分配
|
||
func (m *UserRoleMapping) Revoke() {
|
||
m.IsActive = false
|
||
m.UpdatedAt = nowPtr()
|
||
}
|
||
|
||
// Grant 重新授予角色
|
||
func (m *UserRoleMapping) Grant() {
|
||
m.IsActive = true
|
||
m.UpdatedAt = nowPtr()
|
||
}
|
||
|
||
// IncrementVersion 递增版本号
|
||
func (m *UserRoleMapping) IncrementVersion() {
|
||
m.Version++
|
||
m.UpdatedAt = nowPtr()
|
||
}
|
||
|
||
// ExtendExpiration 延长过期时间
|
||
func (m *UserRoleMapping) ExtendExpiration(newExpiresAt *time.Time) {
|
||
m.ExpiresAt = newExpiresAt
|
||
m.UpdatedAt = nowPtr()
|
||
}
|
||
|
||
// UserRoleMappingInfo 用户-角色映射信息(用于API响应)
|
||
type UserRoleMappingInfo struct {
|
||
UserID int64 `json:"user_id"`
|
||
RoleID int64 `json:"role_id"`
|
||
TenantID int64 `json:"tenant_id"`
|
||
IsActive bool `json:"is_active"`
|
||
ExpiresAt *string `json:"expires_at,omitempty"`
|
||
}
|
||
|
||
// ToInfo 转换为映射信息
|
||
func (m *UserRoleMapping) ToInfo() *UserRoleMappingInfo {
|
||
info := &UserRoleMappingInfo{
|
||
UserID: m.UserID,
|
||
RoleID: m.RoleID,
|
||
TenantID: m.TenantID,
|
||
IsActive: m.IsActive,
|
||
}
|
||
if m.ExpiresAt != nil {
|
||
expStr := m.ExpiresAt.Format(time.RFC3339)
|
||
info.ExpiresAt = &expStr
|
||
}
|
||
return info
|
||
}
|
||
|
||
// UserRoleAssignmentInfo 用户角色分配详情(用于API响应)
|
||
type UserRoleAssignmentInfo struct {
|
||
UserID int64 `json:"user_id"`
|
||
RoleCode string `json:"role_code"`
|
||
RoleName string `json:"role_name"`
|
||
TenantID int64 `json:"tenant_id"`
|
||
GrantedBy int64 `json:"granted_by"`
|
||
GrantedAt string `json:"granted_at"`
|
||
ExpiresAt string `json:"expires_at,omitempty"`
|
||
IsActive bool `json:"is_active"`
|
||
IsExpired bool `json:"is_expired"`
|
||
}
|
||
|
||
// UserRoleWithDetails 用户角色分配(含角色详情)
|
||
type UserRoleWithDetails struct {
|
||
*UserRoleMapping
|
||
RoleCode string
|
||
RoleName string
|
||
}
|
||
|
||
// ToAssignmentInfo 转换为分配详情
|
||
func (m *UserRoleWithDetails) ToAssignmentInfo() *UserRoleAssignmentInfo {
|
||
info := &UserRoleAssignmentInfo{
|
||
UserID: m.UserID,
|
||
RoleCode: m.RoleCode,
|
||
RoleName: m.RoleName,
|
||
TenantID: m.TenantID,
|
||
GrantedBy: m.GrantedBy,
|
||
IsActive: m.IsActive,
|
||
IsExpired: m.IsExpired(),
|
||
}
|
||
if m.GrantedAt != nil {
|
||
info.GrantedAt = m.GrantedAt.Format(time.RFC3339)
|
||
}
|
||
if m.ExpiresAt != nil {
|
||
info.ExpiresAt = m.ExpiresAt.Format(time.RFC3339)
|
||
}
|
||
return info
|
||
}
|