Files
aiops/backend/model/user.go
T
attacker be2a377f01 feat(rbac): F3 前端 RBAC 按钮级控制
后端:
- 新增 GET /user/permissions 端点返回当前用户权限码
- Login 响应附带 permissions 数组
- collectUserPermissionCodes 用 raw SQL JOIN 避免 GORM many2many 表名问题
- admin 用户返回 ['*'] 通配符

前端:
- usePermission hook (hasPermission/hasAnyPermission/hasAllPermissions)
- <HasPermission> 组件 (permission/anyOf/allOf + fallback)
- zustand store 新增 permissions 字段
- Sidebar 菜单递归过滤 (42 菜单项全部标注 permission)
- ServerManager: 添加/导入/批量删除按钮按权限显隐
- ServerTableRow: 终端/编辑/文件/删除按权限显隐
- SystemUserTab: 新建/导入/编辑/删除按钮按权限显隐
- MainLayout: 页面刷新自动拉取权限
- Login: 登录时存储 permissions

验证:
- admin: permissions=['*'] 通配符
- viewer: 7 个只读权限 (dashboard:view/server:view/...)
- viewer 无 server:create/delete
- 10/10 回归测试通过
- npm run build 零错误
2026-06-25 22:51:25 +08:00

203 lines
7.5 KiB
Go

package model
import (
"time"
)
// User 用户模型
type User struct {
ID uint `gorm:"primarykey" json:"id"`
Username string `gorm:"size:64;uniqueIndex;not null" json:"username"`
Password string `gorm:"size:255;not null" json:"-"`
Email string `gorm:"size:128" json:"email"`
Phone string `gorm:"size:32" json:"phone"`
RealName string `gorm:"size:64" json:"real_name"`
Avatar string `gorm:"size:255" json:"avatar"`
Status int `gorm:"default:1" json:"status"` // 0:禁用 1:启用
IsAdmin bool `gorm:"default:false" json:"is_admin"`
AuthSource string `gorm:"size:20;default:'local'" json:"auth_source"` // local / ldap
LastLogin *time.Time `json:"last_login"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
// 关联
Roles []Role `gorm:"many2many:iam_user_roles;" json:"roles,omitempty"`
}
// TableName 表名
func (User) TableName() string {
return "iam_users"
}
// Role 角色模型
type Role struct {
ID uint `gorm:"primarykey" json:"id"`
Name string `gorm:"size:64;uniqueIndex;not null" json:"name"`
Code string `gorm:"size:64;uniqueIndex;not null" json:"code"`
Description string `gorm:"size:255" json:"description"`
Status int `gorm:"default:1" json:"status"`
IsSystem bool `gorm:"default:false" json:"is_system"` // 系统默认角色,禁止删除
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
// 关联
Permissions []Permission `gorm:"many2many:role_permissions;" json:"permissions,omitempty"`
}
// TableName 表名
func (Role) TableName() string {
return "iam_roles"
}
// Permission 权限模型
type Permission struct {
ID uint `gorm:"primarykey" json:"id"`
Name string `gorm:"size:64;not null" json:"name"`
Code string `gorm:"size:128;uniqueIndex;not null" json:"code"`
Type string `gorm:"size:32" json:"type"` // menu, button, api
Path string `gorm:"size:255" json:"path"`
Method string `gorm:"size:32" json:"method"`
ParentID *uint `json:"parent_id"`
Sort int `gorm:"default:0" json:"sort"`
Status int `gorm:"default:1" json:"status"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// TableName 表名
func (Permission) TableName() string {
return "iam_permissions"
}
// ItemRole Jenkins-style Item Role — regex pipeline code matching
type ItemRole struct {
ID uint `gorm:"primarykey" json:"id"`
Name string `gorm:"size:64;not null" json:"name"`
Code string `gorm:"size:64;uniqueIndex;not null" json:"code"`
Pattern string `gorm:"size:255;not null;comment:正则表达式匹配流水线code" json:"pattern"`
Role string `gorm:"size:16;default:'editor';comment:角色owner/editor/viewer" json:"role"`
Description string `gorm:"size:255" json:"description"`
Status int `gorm:"default:1;comment:0禁用1启用" json:"status"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// TableName 表名
func (ItemRole) TableName() string {
return "iam_item_roles"
}
// UserItemRole user ↔ item_role association
type UserItemRole struct {
ID uint `gorm:"primarykey" json:"id"`
UserID uint `gorm:"uniqueIndex:idx_user_item_role;not null" json:"user_id"`
ItemRoleID uint `gorm:"uniqueIndex:idx_user_item_role;not null" json:"item_role_id"`
CreatedAt time.Time `json:"created_at"`
User *User `json:"user,omitempty" gorm:"foreignKey:UserID"`
ItemRole *ItemRole `json:"item_role,omitempty" gorm:"foreignKey:ItemRoleID"`
}
// TableName 表名
func (UserItemRole) TableName() string {
return "iam_user_item_roles"
}
// LoginRequest 登录请求
type LoginRequest struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
// LoginResponse 登录响应
type LoginResponse struct {
Token string `json:"token"`
ExpiresIn int `json:"expires_in"`
User *User `json:"user"`
}
// CreateUserRequest 创建用户请求
type CreateUserRequest struct {
Username string `json:"username" binding:"required,min=3,max=64"`
Password string `json:"password" binding:"required,min=6,max=32"`
Email string `json:"email" binding:"required,email"`
Phone string `json:"phone"`
RealName string `json:"real_name"`
RoleIDs []uint `json:"role_ids"`
}
// UpdateUserRequest 更新用户请求
type UpdateUserRequest struct {
Email string `json:"email" binding:"omitempty,email"`
Phone string `json:"phone"`
RealName string `json:"real_name"`
Status *int `json:"status"`
RoleIDs []uint `json:"role_ids"`
}
// CreateRoleRequest 创建角色请求 // Logan.Li
type CreateRoleRequest struct {
Name string `json:"name" binding:"required,min=1,max=64"`
Code string `json:"code" binding:"required,min=1,max=64"`
Description string `json:"description"`
PermissionIDs []uint `json:"permission_ids"`
}
// UpdateRoleRequest 更新角色请求 // Logan.Li
type UpdateRoleRequest struct {
Name string `json:"name" binding:"omitempty,min=1,max=64"`
Code string `json:"code" binding:"omitempty,min=1,max=64"`
Description *string `json:"description"`
Status *int `json:"status"`
PermissionIDs []uint `json:"permission_ids"`
}
// CreateItemRoleRequest 创建Item Role请求
type CreateItemRoleRequest struct {
Name string `json:"name" binding:"required,min=1,max=64"`
Code string `json:"code" binding:"required,min=1,max=64"`
Pattern string `json:"pattern" binding:"required,max=255"`
Role string `json:"role" binding:"oneof=owner editor viewer"`
Description string `json:"description"`
}
// UpdateItemRoleRequest 更新Item Role请求
type UpdateItemRoleRequest struct {
Name string `json:"name" binding:"omitempty,min=1,max=64"`
Code string `json:"code" binding:"omitempty,min=1,max=64"`
Pattern string `json:"pattern" binding:"omitempty,max=255"`
Role string `json:"role" binding:"omitempty,oneof=owner editor viewer"`
Description string `json:"description"`
Status *int `json:"status"`
}
// AssignItemRoleRequest 分配Item Role给用户
type AssignItemRoleRequest struct {
UserID uint `json:"user_id" binding:"required"`
ItemRoleID uint `json:"item_role_id" binding:"required"`
}
// ChangePasswordRequest 修改密码请求
type ChangePasswordRequest struct {
OldPassword string `json:"old_password" binding:"required"`
NewPassword string `json:"new_password" binding:"required,min=6,max=32"`
}
// LDAPConfig LDAP配置
type LDAPConfig struct {
ID int `gorm:"primarykey" json:"id"`
LDAPHost string `gorm:"size:200;not null" json:"ldap_host"`
LDAPPort *int `json:"ldap_port"`
UseLDAPS *bool `json:"use_ldaps"`
AdminDN string `gorm:"size:500;not null" json:"admin_dn"`
AdminPassword string `gorm:"size:500;not null" json:"admin_password"`
SearchFilter *string `gorm:"size:500" json:"search_filter"`
BaseDN string `gorm:"size:500;not null" json:"base_dn"`
UserMapping *string `gorm:"type:text" json:"user_mapping"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (LDAPConfig) TableName() string { return "iam_ldap_configs" }