You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OneAuth/api/middleware/perm.go

156 lines
3.1 KiB
Go

//
// Copyright (C) 2024 veypi <i@veypi.com>
// 2025-03-04 16:08:06
// Distributed under terms of the MIT license.
//
package middleware
import (
"strings"
"github.com/veypi/vbase/cfg"
"github.com/veypi/vbase/models"
"github.com/veypi/vigo"
)
// Checker 权限检查器
type Checker struct {
userID string
orgID string
roles []string
org *models.Org
}
// NewChecker 创建权限检查器
func NewChecker(x *vigo.X) *Checker {
c := &Checker{}
if uid, ok := x.Get("user_id").(string); ok {
c.userID = uid
}
if oid, ok := x.Get("org_id").(string); ok {
c.orgID = oid
}
if roles, ok := x.Get("org_roles").(string); ok && roles != "" {
c.roles = strings.Split(roles, ",")
}
return c
}
// IsOrgOwner 检查用户是否是组织所有者
func (c *Checker) IsOrgOwner() bool {
if c.orgID == "" || c.userID == "" {
return false
}
if c.org != nil {
return c.org.OwnerID == c.userID
}
var org models.Org
if err := cfg.DB().First(&org, "id = ?", c.orgID).Error; err != nil {
return false
}
c.org = &org
return org.OwnerID == c.userID
}
// IsOrgAdmin 检查用户是否是组织管理员
func (c *Checker) IsOrgAdmin() bool {
if c.IsOrgOwner() {
return true
}
for _, roleID := range c.roles {
var role models.Role
if err := cfg.DB().First(&role, "id = ?", roleID).Error; err != nil {
continue
}
if role.Code == models.RoleCodeAdmin {
return true
}
}
return false
}
// HasRole 检查用户是否有指定角色
func (c *Checker) HasRole(roleCode string) bool {
for _, roleID := range c.roles {
var role models.Role
if err := cfg.DB().First(&role, "id = ?", roleID).Error; err != nil {
continue
}
if role.Code == roleCode {
return true
}
}
return false
}
// RequireAdmin 要求管理员权限
func (c *Checker) RequireAdmin() error {
if !c.IsOrgAdmin() {
return vigo.ErrForbidden.WithString("admin permission required")
}
return nil
}
// RequireOwner 要求所有者权限
func (c *Checker) RequireOwner() error {
if !c.IsOrgOwner() {
return vigo.ErrForbidden.WithString("owner permission required")
}
return nil
}
// RequireOrg 要求必须在组织上下文中
func (c *Checker) RequireOrg() error {
if c.orgID == "" {
return vigo.ErrArgInvalid.WithString("organization context required")
}
return nil
}
// UserID 获取用户ID
func (c *Checker) UserID() string {
return c.userID
}
// OrgID 获取组织ID
func (c *Checker) OrgID() string {
return c.orgID
}
// GetUserRoles 获取用户角色列表
func (c *Checker) GetUserRoles() []string {
return c.roles
}
// RequireAdmin 中间件:要求管理员权限
func RequireAdmin() func(*vigo.X) error {
return func(x *vigo.X) error {
checker := NewChecker(x)
return checker.RequireAdmin()
}
}
// RequireOwner 中间件:要求组织所有者权限
func RequireOwner() func(*vigo.X) error {
return func(x *vigo.X) error {
checker := NewChecker(x)
return checker.RequireOwner()
}
}
// RequireOrgContext 中间件:要求必须在组织上下文中
func RequireOrgContext() func(*vigo.X) error {
return func(x *vigo.X) error {
checker := NewChecker(x)
return checker.RequireOrg()
}
}