|
|
//
|
|
|
// Copyright (C) 2024 veypi <i@veypi.com>
|
|
|
// 2025-02-14 16:08:06
|
|
|
// Distributed under terms of the MIT license.
|
|
|
//
|
|
|
|
|
|
package auth
|
|
|
|
|
|
import (
|
|
|
"context"
|
|
|
"fmt"
|
|
|
"strings"
|
|
|
"time"
|
|
|
|
|
|
"github.com/veypi/vbase/cfg"
|
|
|
"github.com/veypi/vbase/models"
|
|
|
"github.com/veypi/vigo"
|
|
|
)
|
|
|
|
|
|
// Auth 权限管理接口
|
|
|
type Auth interface {
|
|
|
// ========== 中间件生成 ==========
|
|
|
// 基础权限检查
|
|
|
Perm(permissionID string) func(*vigo.X) error
|
|
|
|
|
|
// 资源所有者权限
|
|
|
PermWithOwner(permissionID, ownerKey string) func(*vigo.X) error
|
|
|
|
|
|
// 特定资源权限检查 (自动从 Path/Query 获取资源ID)
|
|
|
PermOnResource(permissionID, resourceKey string) func(*vigo.X) error
|
|
|
|
|
|
// 满足任一权限
|
|
|
PermAny(permissionIDs []string) func(*vigo.X) error
|
|
|
|
|
|
// 满足所有权限
|
|
|
PermAll(permissionIDs []string) func(*vigo.X) error
|
|
|
|
|
|
// ========== 权限管理 ==========
|
|
|
// 授予角色
|
|
|
GrantRole(ctx context.Context, userID, orgID, roleCode string) error
|
|
|
|
|
|
// 撤销角色
|
|
|
RevokeRole(ctx context.Context, userID, orgID, roleCode string) error
|
|
|
|
|
|
// 授予特定资源权限
|
|
|
GrantResourcePerm(ctx context.Context, userID, orgID, permissionID, resourceID string) error
|
|
|
|
|
|
// 撤销特定资源权限
|
|
|
RevokeResourcePerm(ctx context.Context, userID, orgID, permissionID, resourceID string) error
|
|
|
|
|
|
// 撤销用户所有权限
|
|
|
RevokeAll(ctx context.Context, userID, orgID string) error
|
|
|
|
|
|
// ========== 权限查询 ==========
|
|
|
// 检查权限
|
|
|
CheckPermission(ctx context.Context, userID, orgID, permissionID, resourceID string) (bool, error)
|
|
|
|
|
|
// 列出用户权限
|
|
|
ListUserPermissions(ctx context.Context, userID, orgID string) ([]models.UserPermissionResult, error)
|
|
|
|
|
|
// 列出资源授权用户
|
|
|
ListResourceUsers(ctx context.Context, orgID, permissionID, resourceID string) ([]models.ResourceUser, error)
|
|
|
}
|
|
|
|
|
|
// 全局 Auth 工厂
|
|
|
var Factory = &authFactory{
|
|
|
apps: make(map[string]*appAuth),
|
|
|
}
|
|
|
|
|
|
// VBaseAuth vbase 自身的权限管理实例
|
|
|
// 由 vbase 包在初始化时注入
|
|
|
var (
|
|
|
VBaseAuth = Factory.New("vb", models.AppConfig{
|
|
|
Name: "VBase",
|
|
|
Description: "VBase 基础设施",
|
|
|
DefaultRoles: []models.RoleDefinition{
|
|
|
{Code: "admin", Name: "管理员", Policies: []string{"*:*"}},
|
|
|
{Code: "user", Name: "普通用户", Policies: []string{
|
|
|
"user:read", "user:update",
|
|
|
"org:read", "org:create",
|
|
|
"oauth:client:read", "oauth:client:create", "oauth:client:update", "oauth:client:delete",
|
|
|
}},
|
|
|
},
|
|
|
})
|
|
|
)
|
|
|
|
|
|
type authFactory struct {
|
|
|
apps map[string]*appAuth // appKey -> auth实例
|
|
|
}
|
|
|
|
|
|
// New 创建权限管理实例(注册应用)
|
|
|
func (f *authFactory) New(appKey string, config models.AppConfig) Auth {
|
|
|
if _, exists := f.apps[appKey]; exists {
|
|
|
return f.apps[appKey]
|
|
|
}
|
|
|
|
|
|
auth := &appAuth{
|
|
|
appKey: appKey,
|
|
|
config: config,
|
|
|
}
|
|
|
f.apps[appKey] = auth
|
|
|
return auth
|
|
|
}
|
|
|
|
|
|
// Init 初始化所有注册的权限配置
|
|
|
// - 检查不同 app 之间是否有冲突
|
|
|
// - 同步 Permission 到数据库
|
|
|
// - 建立预设角色
|
|
|
func (f *authFactory) Init() error {
|
|
|
for appKey, auth := range f.apps {
|
|
|
if err := auth.init(); err != nil {
|
|
|
return fmt.Errorf("failed to init auth for %s: %w", appKey, err)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// appAuth 单个应用的权限管理
|
|
|
type appAuth struct {
|
|
|
appKey string
|
|
|
config models.AppConfig
|
|
|
}
|
|
|
|
|
|
// init 初始化应用的权限配置
|
|
|
func (a *appAuth) init() error {
|
|
|
// 1. 同步权限定义到数据库
|
|
|
for _, permDef := range a.extractPermissions() {
|
|
|
var perm models.Permission
|
|
|
err := cfg.DB().Where("id = ?", permDef.ID).First(&perm).Error
|
|
|
if err != nil {
|
|
|
// 不存在则创建
|
|
|
perm = permDef
|
|
|
if err := cfg.DB().Create(&perm).Error; err != nil {
|
|
|
return fmt.Errorf("failed to create permission %s: %w", permDef.ID, err)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 2. 创建系统预设角色
|
|
|
for _, roleDef := range a.config.DefaultRoles {
|
|
|
if err := a.initRole(roleDef); err != nil {
|
|
|
return err
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// extractPermissions 从角色定义中提取所有权限
|
|
|
func (a *appAuth) extractPermissions() []models.Permission {
|
|
|
permMap := make(map[string]models.Permission)
|
|
|
|
|
|
for _, roleDef := range a.config.DefaultRoles {
|
|
|
for _, policy := range roleDef.Policies {
|
|
|
// policy 格式: "resource:action" 或 "*:*"
|
|
|
parts := strings.Split(policy, ":")
|
|
|
if len(parts) != 2 {
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
resource, action := parts[0], parts[1]
|
|
|
permID := fmt.Sprintf("%s:%s:%s", a.appKey, resource, action)
|
|
|
|
|
|
if _, exists := permMap[permID]; !exists {
|
|
|
permMap[permID] = models.Permission{
|
|
|
ID: permID,
|
|
|
AppKey: a.appKey,
|
|
|
Resource: resource,
|
|
|
Action: action,
|
|
|
Description: fmt.Sprintf("%s %s on %s", a.config.Name, action, resource),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
result := make([]models.Permission, 0, len(permMap))
|
|
|
for _, perm := range permMap {
|
|
|
result = append(result, perm)
|
|
|
}
|
|
|
return result
|
|
|
}
|
|
|
|
|
|
// initRole 初始化系统预设角色
|
|
|
func (a *appAuth) initRole(roleDef models.RoleDefinition) error {
|
|
|
// 查找或创建系统角色
|
|
|
var role models.Role
|
|
|
err := cfg.DB().Where("code = ? AND org_id = ''", roleDef.Code).First(&role).Error
|
|
|
if err != nil {
|
|
|
// 创建新角色
|
|
|
role = models.Role{
|
|
|
OrgID: "",
|
|
|
Code: roleDef.Code,
|
|
|
Name: roleDef.Name,
|
|
|
Description: roleDef.Description,
|
|
|
IsSystem: true,
|
|
|
Status: 1,
|
|
|
}
|
|
|
if err := cfg.DB().Create(&role).Error; err != nil {
|
|
|
return fmt.Errorf("failed to create role %s: %w", roleDef.Code, err)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 同步角色权限
|
|
|
for _, policy := range roleDef.Policies {
|
|
|
parts := strings.Split(policy, ":")
|
|
|
if len(parts) != 2 {
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
resource, action := parts[0], parts[1]
|
|
|
permID := fmt.Sprintf("%s:%s:%s", a.appKey, resource, action)
|
|
|
|
|
|
// 检查关联是否存在
|
|
|
var count int64
|
|
|
cfg.DB().Model(&models.RolePermission{}).
|
|
|
Where("role_id = ? AND permission_id = ?", role.ID, permID).
|
|
|
Count(&count)
|
|
|
|
|
|
if count == 0 {
|
|
|
rp := models.RolePermission{
|
|
|
RoleID: role.ID,
|
|
|
PermissionID: permID,
|
|
|
Condition: "none",
|
|
|
}
|
|
|
if err := cfg.DB().Create(&rp).Error; err != nil {
|
|
|
return fmt.Errorf("failed to create role permission: %w", err)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// ========== 中间件实现 ==========
|
|
|
|
|
|
func (a *appAuth) Perm(permissionID string) func(*vigo.X) error {
|
|
|
return func(x *vigo.X) error {
|
|
|
userID := getUserID(x)
|
|
|
if userID == "" {
|
|
|
return vigo.ErrUnauthorized
|
|
|
}
|
|
|
|
|
|
orgID := getOrgID(x)
|
|
|
|
|
|
ok, err := a.CheckPermission(x.Context(), userID, orgID, permissionID, "")
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
if !ok {
|
|
|
return vigo.ErrForbidden
|
|
|
}
|
|
|
return nil
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (a *appAuth) PermWithOwner(permissionID, ownerKey string) func(*vigo.X) error {
|
|
|
return func(x *vigo.X) error {
|
|
|
userID := getUserID(x)
|
|
|
if userID == "" {
|
|
|
return vigo.ErrUnauthorized
|
|
|
}
|
|
|
|
|
|
orgID := getOrgID(x)
|
|
|
|
|
|
// 先检查是否有权限
|
|
|
ok, err := a.CheckPermission(x.Context(), userID, orgID, permissionID, "")
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
if !ok {
|
|
|
return vigo.ErrForbidden
|
|
|
}
|
|
|
|
|
|
// 检查是否是所有者或管理员
|
|
|
ownerID, _ := x.Get(ownerKey).(string)
|
|
|
if ownerID == "" {
|
|
|
ownerID = x.PathParams.Get(ownerKey)
|
|
|
}
|
|
|
if ownerID == userID {
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// 检查是否是管理员
|
|
|
isAdmin, _ := a.isAdmin(x.Context(), userID, orgID)
|
|
|
if isAdmin {
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
return vigo.ErrForbidden
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (a *appAuth) PermOnResource(permissionID, resourceKey string) func(*vigo.X) error {
|
|
|
return func(x *vigo.X) error {
|
|
|
userID := getUserID(x)
|
|
|
if userID == "" {
|
|
|
return vigo.ErrUnauthorized
|
|
|
}
|
|
|
|
|
|
orgID := getOrgID(x)
|
|
|
|
|
|
// 尝试从 PathParams 获取
|
|
|
resourceID := x.PathParams.Get(resourceKey)
|
|
|
if resourceID == "" {
|
|
|
// 尝试从 Query 获取
|
|
|
resourceID = x.Request.URL.Query().Get(resourceKey)
|
|
|
}
|
|
|
|
|
|
// 如果没有获取到 resourceID,仍然进行检查 (resourceID="")
|
|
|
// 这意味着检查用户是否拥有该权限的一般访问权 (例如通过角色获得)
|
|
|
// 如果想要强制检查特定资源,调用方应该确保 resourceKey 能获取到值
|
|
|
|
|
|
ok, err := a.CheckPermission(x.Context(), userID, orgID, permissionID, resourceID)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
if !ok {
|
|
|
return vigo.ErrForbidden
|
|
|
}
|
|
|
return nil
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (a *appAuth) PermAny(permissionIDs []string) func(*vigo.X) error {
|
|
|
return func(x *vigo.X) error {
|
|
|
userID := getUserID(x)
|
|
|
if userID == "" {
|
|
|
return vigo.ErrUnauthorized
|
|
|
}
|
|
|
|
|
|
orgID := getOrgID(x)
|
|
|
|
|
|
for _, permID := range permissionIDs {
|
|
|
ok, err := a.CheckPermission(x.Context(), userID, orgID, permID, "")
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
if ok {
|
|
|
return nil
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return vigo.ErrForbidden
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (a *appAuth) PermAll(permissionIDs []string) func(*vigo.X) error {
|
|
|
return func(x *vigo.X) error {
|
|
|
userID := getUserID(x)
|
|
|
if userID == "" {
|
|
|
return vigo.ErrUnauthorized
|
|
|
}
|
|
|
|
|
|
orgID := getOrgID(x)
|
|
|
|
|
|
for _, permID := range permissionIDs {
|
|
|
ok, err := a.CheckPermission(x.Context(), userID, orgID, permID, "")
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
if !ok {
|
|
|
return vigo.ErrForbidden
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// ========== 权限管理实现 ==========
|
|
|
|
|
|
func (a *appAuth) GrantRole(ctx context.Context, userID, orgID, roleCode string) error {
|
|
|
// 查找角色
|
|
|
var role models.Role
|
|
|
query := cfg.DB().Where("code = ?", roleCode)
|
|
|
if orgID != "" {
|
|
|
query = query.Where("org_id = ?", orgID)
|
|
|
} else {
|
|
|
query = query.Where("org_id = ''")
|
|
|
}
|
|
|
|
|
|
if err := query.First(&role).Error; err != nil {
|
|
|
// 如果指定了 OrgID 但没找到,尝试查找全局角色
|
|
|
if orgID != "" {
|
|
|
query = cfg.DB().Where("code = ? AND org_id = ''", roleCode)
|
|
|
if err := query.First(&role).Error; err != nil {
|
|
|
return fmt.Errorf("role not found: %s", roleCode)
|
|
|
}
|
|
|
} else {
|
|
|
return fmt.Errorf("role not found: %s", roleCode)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 检查是否已存在
|
|
|
var count int64
|
|
|
cfg.DB().Model(&models.UserRole{}).
|
|
|
Where("user_id = ? AND org_id = ? AND role_id = ?", userID, orgID, role.ID).
|
|
|
Count(&count)
|
|
|
|
|
|
if count > 0 {
|
|
|
return nil // 已存在
|
|
|
}
|
|
|
|
|
|
userRole := models.UserRole{
|
|
|
UserID: userID,
|
|
|
OrgID: orgID,
|
|
|
RoleID: role.ID,
|
|
|
ExpireAt: nil, // 默认不过期
|
|
|
}
|
|
|
|
|
|
return cfg.DB().Create(&userRole).Error
|
|
|
}
|
|
|
|
|
|
func (a *appAuth) RevokeRole(ctx context.Context, userID, orgID, roleCode string) error {
|
|
|
var role models.Role
|
|
|
// 优先查找组织特定角色
|
|
|
query := cfg.DB().Where("code = ?", roleCode)
|
|
|
if orgID != "" {
|
|
|
query = query.Where("org_id = ?", orgID)
|
|
|
} else {
|
|
|
query = query.Where("org_id = ''")
|
|
|
}
|
|
|
|
|
|
if err := query.First(&role).Error; err != nil {
|
|
|
// 如果没找到,尝试查找全局角色
|
|
|
if orgID != "" {
|
|
|
if err := cfg.DB().Where("code = ? AND org_id = ''", roleCode).First(&role).Error; err != nil {
|
|
|
return nil // 角色不存在,无需撤销
|
|
|
}
|
|
|
} else {
|
|
|
return nil
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return cfg.DB().Where("user_id = ? AND org_id = ? AND role_id = ?", userID, orgID, role.ID).
|
|
|
Delete(&models.UserRole{}).Error
|
|
|
}
|
|
|
|
|
|
func (a *appAuth) GrantResourcePerm(ctx context.Context, userID, orgID, permissionID, resourceID string) error {
|
|
|
if strings.Count(permissionID, ":") == 1 {
|
|
|
permissionID = fmt.Sprintf("%s:%s", a.appKey, permissionID)
|
|
|
}
|
|
|
// 检查权限是否存在
|
|
|
var perm models.Permission
|
|
|
if err := cfg.DB().Where("id = ?", permissionID).First(&perm).Error; err != nil {
|
|
|
return fmt.Errorf("permission not found: %s", permissionID)
|
|
|
}
|
|
|
|
|
|
// 检查是否已存在
|
|
|
var existing models.UserPermission
|
|
|
err := cfg.DB().Where("user_id = ? AND org_id = ? AND permission_id = ? AND resource_id = ?",
|
|
|
userID, orgID, permissionID, resourceID).
|
|
|
First(&existing).Error
|
|
|
|
|
|
if err == nil {
|
|
|
// 已存在
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
userPerm := models.UserPermission{
|
|
|
UserID: userID,
|
|
|
OrgID: orgID,
|
|
|
PermissionID: permissionID,
|
|
|
ResourceID: resourceID,
|
|
|
ExpireAt: nil, // 默认不过期
|
|
|
GrantedBy: "", // 默认空
|
|
|
}
|
|
|
|
|
|
return cfg.DB().Create(&userPerm).Error
|
|
|
}
|
|
|
|
|
|
func (a *appAuth) RevokeResourcePerm(ctx context.Context, userID, orgID, permissionID, resourceID string) error {
|
|
|
if strings.Count(permissionID, ":") == 1 {
|
|
|
permissionID = fmt.Sprintf("%s:%s", a.appKey, permissionID)
|
|
|
}
|
|
|
return cfg.DB().Where("user_id = ? AND org_id = ? AND permission_id = ? AND resource_id = ?",
|
|
|
userID, orgID, permissionID, resourceID).
|
|
|
Delete(&models.UserPermission{}).Error
|
|
|
}
|
|
|
|
|
|
func (a *appAuth) RevokeAll(ctx context.Context, userID, orgID string) error {
|
|
|
// 删除用户角色
|
|
|
if err := cfg.DB().Where("user_id = ? AND org_id = ?", userID, orgID).
|
|
|
Delete(&models.UserRole{}).Error; err != nil {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
// 删除用户特定权限
|
|
|
if err := cfg.DB().Where("user_id = ? AND org_id = ?", userID, orgID).
|
|
|
Delete(&models.UserPermission{}).Error; err != nil {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// ========== 权限查询实现 ==========
|
|
|
|
|
|
func (a *appAuth) CheckPermission(ctx context.Context, userID, orgID, permissionID, resourceID string) (bool, error) {
|
|
|
if strings.Count(permissionID, ":") == 1 {
|
|
|
permissionID = fmt.Sprintf("%s:%s", a.appKey, permissionID)
|
|
|
}
|
|
|
|
|
|
fmt.Printf("[DEBUG] CheckPermission: userID=%s, orgID=%s, permID=%s, resID=%s\n", userID, orgID, permissionID, resourceID)
|
|
|
|
|
|
// 1. 检查用户是否有该权限的角色(包括当前组织角色和系统全局角色)
|
|
|
var roleIDs []string
|
|
|
roleQuery := cfg.DB().Model(&models.UserRole{}).
|
|
|
Where("user_id = ? AND (expire_at IS NULL OR expire_at > ?)", userID, time.Now())
|
|
|
|
|
|
if orgID != "" {
|
|
|
roleQuery = roleQuery.Where("org_id = ? OR org_id = ''", orgID)
|
|
|
} else {
|
|
|
roleQuery = roleQuery.Where("org_id = ''")
|
|
|
}
|
|
|
|
|
|
if err := roleQuery.Pluck("role_id", &roleIDs).Error; err != nil {
|
|
|
fmt.Printf("[DEBUG] CheckPermission: failed to get roles: %v\n", err)
|
|
|
return false, err
|
|
|
}
|
|
|
fmt.Printf("[DEBUG] CheckPermission: roleIDs=%v\n", roleIDs)
|
|
|
|
|
|
if len(roleIDs) > 0 {
|
|
|
// 构造可能的通配符权限ID
|
|
|
permsToCheck := []string{permissionID}
|
|
|
parts := strings.Split(permissionID, ":")
|
|
|
if len(parts) == 3 {
|
|
|
// app:resource:*
|
|
|
permsToCheck = append(permsToCheck, fmt.Sprintf("%s:%s:*", parts[0], parts[1]))
|
|
|
// app:*:*
|
|
|
permsToCheck = append(permsToCheck, fmt.Sprintf("%s:*:*", parts[0]))
|
|
|
}
|
|
|
|
|
|
// 检查这些角色是否有所需权限
|
|
|
var count int64
|
|
|
if err := cfg.DB().Model(&models.RolePermission{}).
|
|
|
Where("role_id IN ? AND permission_id IN ?", roleIDs, permsToCheck).
|
|
|
Count(&count).Error; err != nil {
|
|
|
return false, err
|
|
|
}
|
|
|
fmt.Printf("[DEBUG] CheckPermission: role perm count=%d checked=%v\n", count, permsToCheck)
|
|
|
if count > 0 {
|
|
|
return true, nil
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 2. 检查用户是否有特定的资源权限
|
|
|
// 构造可能的通配符权限ID (同上)
|
|
|
permsToCheck := []string{permissionID}
|
|
|
parts := strings.Split(permissionID, ":")
|
|
|
if len(parts) == 3 {
|
|
|
permsToCheck = append(permsToCheck, fmt.Sprintf("%s:%s:*", parts[0], parts[1]))
|
|
|
permsToCheck = append(permsToCheck, fmt.Sprintf("%s:*:*", parts[0]))
|
|
|
}
|
|
|
|
|
|
var userPermCount int64
|
|
|
query := cfg.DB().Model(&models.UserPermission{}).
|
|
|
Where("user_id = ? AND org_id = ? AND permission_id IN ? AND (expire_at IS NULL OR expire_at > ?)",
|
|
|
userID, orgID, permsToCheck, time.Now())
|
|
|
|
|
|
if resourceID != "" {
|
|
|
query = query.Where("resource_id = ? OR resource_id = '*'", resourceID)
|
|
|
}
|
|
|
|
|
|
if err := query.Count(&userPermCount).Error; err != nil {
|
|
|
return false, err
|
|
|
}
|
|
|
|
|
|
return userPermCount > 0, nil
|
|
|
}
|
|
|
|
|
|
func (a *appAuth) ListUserPermissions(ctx context.Context, userID, orgID string) ([]models.UserPermissionResult, error) {
|
|
|
result := make([]models.UserPermissionResult, 0)
|
|
|
|
|
|
// 1. 获取用户角色对应的权限
|
|
|
var roleIDs []string
|
|
|
if err := cfg.DB().Model(&models.UserRole{}).
|
|
|
Where("user_id = ? AND org_id = ? AND (expire_at IS NULL OR expire_at > ?)",
|
|
|
userID, orgID, time.Now()).
|
|
|
Pluck("role_id", &roleIDs).Error; err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
if len(roleIDs) > 0 {
|
|
|
var permIDs []string
|
|
|
if err := cfg.DB().Model(&models.RolePermission{}).
|
|
|
Where("role_id IN ?", roleIDs).
|
|
|
Pluck("permission_id", &permIDs).Error; err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
for _, permID := range permIDs {
|
|
|
result = append(result, models.UserPermissionResult{
|
|
|
PermissionID: permID,
|
|
|
ResourceID: "*",
|
|
|
Actions: []string{"*"},
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 2. 获取用户特定资源权限
|
|
|
var userPerms []models.UserPermission
|
|
|
if err := cfg.DB().Where("user_id = ? AND org_id = ? AND (expire_at IS NULL OR expire_at > ?)",
|
|
|
userID, orgID, time.Now()).
|
|
|
Find(&userPerms).Error; err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
for _, up := range userPerms {
|
|
|
result = append(result, models.UserPermissionResult{
|
|
|
PermissionID: up.PermissionID,
|
|
|
ResourceID: up.ResourceID,
|
|
|
Actions: []string{"*"},
|
|
|
})
|
|
|
}
|
|
|
|
|
|
return result, nil
|
|
|
}
|
|
|
|
|
|
func (a *appAuth) ListResourceUsers(ctx context.Context, orgID, permissionID, resourceID string) ([]models.ResourceUser, error) {
|
|
|
result := make([]models.ResourceUser, 0)
|
|
|
|
|
|
// 查询有该资源权限的用户
|
|
|
var userPerms []models.UserPermission
|
|
|
query := cfg.DB().Where("org_id = ? AND permission_id = ?", orgID, permissionID)
|
|
|
if resourceID != "" {
|
|
|
query = query.Where("resource_id = ? OR resource_id = '*'", resourceID)
|
|
|
}
|
|
|
|
|
|
if err := query.Find(&userPerms).Error; err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
userMap := make(map[string][]string)
|
|
|
for _, up := range userPerms {
|
|
|
userMap[up.UserID] = append(userMap[up.UserID], "*")
|
|
|
}
|
|
|
|
|
|
for userID, actions := range userMap {
|
|
|
result = append(result, models.ResourceUser{
|
|
|
UserID: userID,
|
|
|
Actions: actions,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
return result, nil
|
|
|
}
|
|
|
|
|
|
// ========== 辅助方法 ==========
|
|
|
|
|
|
func (a *appAuth) isAdmin(ctx context.Context, userID, orgID string) (bool, error) {
|
|
|
// 检查用户是否有管理员角色
|
|
|
var adminRoleIDs []string
|
|
|
if err := cfg.DB().Model(&models.Role{}).
|
|
|
Where("code = 'admin'").
|
|
|
Pluck("id", &adminRoleIDs).Error; err != nil {
|
|
|
return false, err
|
|
|
}
|
|
|
|
|
|
if len(adminRoleIDs) == 0 {
|
|
|
return false, nil
|
|
|
}
|
|
|
|
|
|
var count int64
|
|
|
if err := cfg.DB().Model(&models.UserRole{}).
|
|
|
Where("user_id = ? AND org_id = ? AND role_id IN ?", userID, orgID, adminRoleIDs).
|
|
|
Count(&count).Error; err != nil {
|
|
|
return false, err
|
|
|
}
|
|
|
|
|
|
return count > 0, nil
|
|
|
}
|
|
|
|
|
|
// 从 context 获取用户ID
|
|
|
func getUserID(x *vigo.X) string {
|
|
|
if userID, ok := x.Get("user_id").(string); ok {
|
|
|
return userID
|
|
|
}
|
|
|
return ""
|
|
|
}
|
|
|
|
|
|
// 从 context 获取组织ID
|
|
|
func getOrgID(x *vigo.X) string {
|
|
|
if orgID, ok := x.Get("org_id").(string); ok {
|
|
|
return orgID
|
|
|
}
|
|
|
return ""
|
|
|
}
|