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

161 lines
4.8 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 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)
}