thread-master/apps/backend/internal/module/permission/permission.go

161 lines
4.8 KiB
Go
Raw Normal View History

2026-07-13 01:15:30 +00:00
// Package permission — 能力點capability與角色預設對照。
//
// 現行策略M1M2
// - JWT 帶 roles[];中介層/業務用 permission.Has(roles, code) 判定
// - 尚未做 DB 動態 permission 表;擴充時只改本檔 RoleGrants 即可
//
// 命名:{domain}:{resource}:{action} 或 {domain}:{action}
package permission
// ─── 公開/系統(不需登入)────────────────────────────────
const (
// PublicPing 健康檢查(無 JWT
PublicPing = "public:ping"
// PublicAuthLogin 登入註冊忘密refresh 等公開 auth
PublicAuthLogin = "public:auth:login"
// PublicThreadsOAuthCallback OAuth 回調state 驗證)
PublicThreadsOAuthCallback = "public:threads:oauth_callback"
)
// ─── 已登入會員member──────────────────────────────────
const (
AuthMe = "auth:me"
AuthProfileUpdate = "auth:profile:update"
AuthPasswordChange = "auth:password:change"
AuthEmailVerify = "auth:email:verify"
AuthLogout = "auth:logout"
AuthIdentities = "auth:identities"
AuthBind = "auth:bind"
AuthUnbind = "auth:unbind"
MediaUpload = "media:upload"
SettingsAIRead = "settings:ai:read"
SettingsAIWrite = "settings:ai:write"
SettingsPlacementRead = "settings:placement:read"
SettingsPlacementWrite = "settings:placement:write"
SettingsModelsList = "settings:models:list"
ThreadsOAuthStart = "threads:oauth:start"
ThreadsList = "threads:list"
ThreadsRefresh = "threads:refresh"
ThreadsDisconnect = "threads:disconnect"
JobsList = "jobs:list"
JobsGet = "jobs:get"
// JobsDemoCreate 僅 admin任務頁「產生測試任務」
JobsDemoCreate = "jobs:demo:create"
NotifList = "notifications:list"
NotifUnread = "notifications:unread"
NotifMarkRead = "notifications:mark_read"
)
// ─── 管理員admin───────────────────────────────────────
const (
// AdminAccess 進入管理能力的總閘AdminAuth middleware 檢查此碼)
AdminAccess = "admin:access"
AdminMembersList = "admin:members:list"
AdminMembersGet = "admin:members:get"
AdminMembersCreate = "admin:members:create"
AdminMembersSuspend = "admin:members:suspend"
AdminMembersRoles = "admin:members:roles"
AdminMembersEmailVerified = "admin:members:email_verified"
AdminMembersResetPassword = "admin:members:reset_password"
AdminMembersIdentities = "admin:members:identities"
AdminMembersStatus = "admin:members:status"
)
// Role names與 member.domain 一致)
const (
RoleMember = "member"
RoleAdmin = "admin"
)
// memberBase — 一般會員可做的事
var memberBase = []string{
AuthMe, AuthProfileUpdate, AuthPasswordChange, AuthEmailVerify, AuthLogout,
AuthIdentities, AuthBind, AuthUnbind,
MediaUpload,
SettingsAIRead, SettingsAIWrite, SettingsPlacementRead, SettingsPlacementWrite, SettingsModelsList,
ThreadsOAuthStart, ThreadsList, ThreadsRefresh, ThreadsDisconnect,
JobsList, JobsGet,
NotifList, NotifUnread, NotifMarkRead,
}
// adminExtra — 管理員額外能力
var adminExtra = []string{
AdminAccess,
AdminMembersList, AdminMembersGet, AdminMembersCreate,
AdminMembersSuspend, AdminMembersRoles, AdminMembersEmailVerified,
AdminMembersResetPassword, AdminMembersIdentities, AdminMembersStatus,
JobsDemoCreate,
}
// RoleGrants 角色 → 能力列表(可擴充自訂角色)
var RoleGrants = map[string][]string{
RoleMember: memberBase,
RoleAdmin: append(append([]string{}, memberBase...), adminExtra...),
}
// Expand 合併多角色能力(去重)
func Expand(roles []string) map[string]struct{} {
out := make(map[string]struct{})
for _, r := range roles {
for _, p := range RoleGrants[r] {
out[p] = struct{}{}
}
}
// admin 一定含 AdminAccess
if hasRole(roles, RoleAdmin) {
out[AdminAccess] = struct{}{}
}
return out
}
func hasRole(roles []string, want string) bool {
for _, r := range roles {
if r == want {
return true
}
}
return false
}
// Has 是否具備指定 permission
func Has(roles []string, code string) bool {
if code == "" {
return false
}
_, ok := Expand(roles)[code]
return ok
}
// HasAny 具備任一即可
func HasAny(roles []string, codes ...string) bool {
set := Expand(roles)
for _, c := range codes {
if _, ok := set[c]; ok {
return true
}
}
return false
}
// HasAll 必須全部具備
func HasAll(roles []string, codes ...string) bool {
set := Expand(roles)
for _, c := range codes {
if _, ok := set[c]; !ok {
return false
}
}
return true
}
// IsAdmin 是否具管理總閘(相容舊呼叫)
func IsAdmin(roles []string) bool {
return Has(roles, AdminAccess)
}