161 lines
4.8 KiB
Go
161 lines
4.8 KiB
Go
|
|
// Package permission — 能力點(capability)與角色預設對照。
|
|||
|
|
//
|
|||
|
|
// 現行策略(M1~M2):
|
|||
|
|
// - 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)
|
|||
|
|
}
|