backend/pkg/permission/usecase/permission.go

349 lines
11 KiB
Go

package usecase
import (
"backend/pkg/library/errs/code"
"context"
"github.com/zeromicro/go-zero/core/logx"
"go.mongodb.org/mongo-driver/v2/bson"
"backend/pkg/library/errs"
"backend/pkg/permission/domain/entity"
"backend/pkg/permission/domain/repository"
"backend/pkg/permission/domain/usecase"
"github.com/casbin/casbin/v2"
)
type PermissionUseCaseParam struct {
Enforcer *casbin.Enforcer
PermissionRepo repository.PermissionRepository
RoleRepo repository.RoleRepository
UserRoleRepo repository.UserRoleRepository
}
type PermissionUseCase struct {
enforcer *casbin.Enforcer
permissionRepo repository.PermissionRepository
roleRepo repository.RoleRepository
userRoleRepo repository.UserRoleRepository
}
// MustPermissionUseCase 創建權限用例實例
func MustPermissionUseCase(param PermissionUseCaseParam) usecase.PermissionUseCase {
return &PermissionUseCase{
enforcer: param.Enforcer,
permissionRepo: param.PermissionRepo,
roleRepo: param.RoleRepo,
userRoleRepo: param.UserRoleRepo,
}
}
func (uc *PermissionUseCase) CreatePermission(ctx context.Context, req usecase.CreatePermissionRequest) (*entity.Permission, error) {
// 驗證請求
if req.Name == "" {
return nil, errs.InvalidFormat("permission name is required")
}
permission := &entity.Permission{
Name: req.Name,
HTTPMethod: req.HTTPMethod,
HTTPPath: req.HTTPPath,
Status: req.Status,
Type: req.Type,
}
if req.ParentID != nil {
objID, err := bson.ObjectIDFromHex(*req.ParentID)
if err != nil {
e := errs.InvalidFormat(err.Error())
return nil, e
}
permission.ID = objID
}
if err := uc.permissionRepo.Create(ctx, permission); err != nil {
return nil, err
}
return permission, nil
}
func (uc *PermissionUseCase) GetPermission(ctx context.Context, id string) (*entity.Permission, error) {
return uc.permissionRepo.GetByID(ctx, id)
}
func (uc *PermissionUseCase) UpdatePermission(ctx context.Context, req usecase.UpdatePermissionRequest) (*entity.Permission, error) {
// 獲取現有權限
permission, err := uc.permissionRepo.GetByID(ctx, req.ID)
if err != nil {
return nil, err
}
// 更新字段
if req.Name != nil {
permission.Name = *req.Name
}
if req.HTTPMethod != nil {
permission.HTTPMethod = *req.HTTPMethod
}
if req.HTTPPath != nil {
permission.HTTPPath = *req.HTTPPath
}
if req.Status != nil {
permission.Status = *req.Status
}
if req.Type != nil {
permission.Type = *req.Type
}
if err := uc.permissionRepo.Update(ctx, req.ID, permission); err != nil {
return nil, err
}
return permission, nil
}
func (uc *PermissionUseCase) DeletePermission(ctx context.Context, id string) error {
return uc.permissionRepo.Delete(ctx, id)
}
func (uc *PermissionUseCase) ListPermissions(ctx context.Context, req usecase.ListPermissionsRequest) ([]*entity.Permission, error) {
filter := repository.PermissionFilter{
Status: req.Status,
Type: req.Type,
ParentID: req.ParentID,
Limit: req.Limit,
Skip: req.Skip,
}
return uc.permissionRepo.List(ctx, filter)
}
// CheckUserPermission 使用 Casbin 檢查用戶權限
func (uc *PermissionUseCase) CheckUserPermission(ctx context.Context, uid, httpMethod, httpPath string) (bool, error) {
// 使用 Casbin 進行權限檢查
// sub: 用戶ID, obj: 資源路徑, act: 行為
hasPermission, err := uc.enforcer.Enforce(uid, httpPath, httpMethod)
if err != nil {
return false, errs.SystemInternalErrorScope(code.CloudEPPermission, "casbin enforce failed: "+err.Error())
}
if !hasPermission {
return false, errs.InsufficientPermission(httpMethod + ":" + httpPath)
}
return true, nil
}
// CheckRolePermission 使用 Casbin 檢查角色權限
func (uc *PermissionUseCase) CheckRolePermission(ctx context.Context, roleUID, httpMethod, httpPath string) (bool, error) {
// 使用 Casbin 進行角色權限檢查
hasPermission, err := uc.enforcer.Enforce(roleUID, httpPath, httpMethod)
if err != nil {
return false, errs.SystemInternalErrorScope(code.CloudEPPermission, "casbin enforce failed: "+err.Error())
}
if !hasPermission {
return false, errs.InsufficientPermission(httpMethod + ":" + httpPath)
}
return true, nil
}
// GetUserPermissions 獲取用戶的所有權限
func (uc *PermissionUseCase) GetUserPermissions(ctx context.Context, uid string) (map[string]int, error) {
// 獲取用戶的所有角色
roles, err := uc.enforcer.GetRolesForUser(uid)
if err != nil {
return nil, errs.SystemInternalErrorScope(code.CloudEPPermission, "failed to get user permissions: "+err.Error())
}
permissions := make(map[string]int)
// 獲取用戶直接擁有的權限
userPolicies, err := uc.enforcer.GetPermissionsForUser(uid)
if err != nil {
logx.Infof("failed to get user permissions: " + err.Error())
}
for _, policy := range userPolicies {
if len(policy) >= 3 {
key := policy[2] + ":" + policy[1] // method:path
permissions[key] = 1
}
}
// 獲取通過角色繼承的權限
for _, role := range roles {
rolePolicies, err := uc.enforcer.GetPermissionsForUser(role)
if err != nil {
logx.Infof("failed to get permissions for user: " + err.Error())
}
for _, policy := range rolePolicies {
if len(policy) >= 3 {
key := policy[2] + ":" + policy[1] // method:path
permissions[key] = 1
}
}
}
return permissions, nil
}
// BatchCheckPermissions 批量檢查權限
func (uc *PermissionUseCase) BatchCheckPermissions(ctx context.Context, uid string, permissions []usecase.PermissionCheck) (map[string]bool, error) {
results := make(map[string]bool)
for _, perm := range permissions {
key := perm.HTTPMethod + ":" + perm.HTTPPath
hasPermission, err := uc.enforcer.Enforce(uid, perm.HTTPPath, perm.HTTPMethod)
if err != nil {
return nil, errs.SystemInternalErrorScope(code.CloudEPPermission, "casbin enforce failed: "+err.Error())
}
results[key] = hasPermission
}
return results, nil
}
// AddPolicyForUser 為用戶添加權限策略
func (uc *PermissionUseCase) AddPolicyForUser(ctx context.Context, uid, httpPath, httpMethod string) error {
added, err := uc.enforcer.AddPolicy(uid, httpPath, httpMethod)
if err != nil {
return errs.SystemInternalErrorScope(code.CloudEPPermission, "casbin add policy failed: "+err.Error())
}
if !added {
return errs.ResourceAlreadyExistWithScope(code.CloudEPPermission, "policy already exists")
}
return nil
}
// RemovePolicyForUser 移除用戶的權限策略
func (uc *PermissionUseCase) RemovePolicyForUser(ctx context.Context, uid, httpPath, httpMethod string) error {
removed, err := uc.enforcer.RemovePolicy(uid, httpPath, httpMethod)
if err != nil {
return errs.SystemInternalErrorScope(code.CloudEPPermission, "casbin remove policy failed: "+err.Error())
}
if !removed {
return errs.ResourceNotFoundWithScope(code.CloudEPPermission, 0, "policy not found")
}
return nil
}
// AddRoleForUser 為用戶分配角色
func (uc *PermissionUseCase) AddRoleForUser(ctx context.Context, uid, roleUID string) error {
added, err := uc.enforcer.AddRoleForUser(uid, roleUID)
if err != nil {
return errs.SystemInternalErrorScope(code.CloudEPPermission, "casbin add role failed: "+err.Error())
}
if !added {
return errs.ResourceAlreadyExistWithScope(code.CloudEPPermission, "role already assigned")
}
return nil
}
// RemoveRoleForUser 移除用戶的角色
func (uc *PermissionUseCase) RemoveRoleForUser(ctx context.Context, uid, roleUID string) error {
removed, err := uc.enforcer.DeleteRoleForUser(uid, roleUID)
if err != nil {
return errs.SystemInternalErrorScope(code.CloudEPPermission, "casbin remove role failed: "+err.Error())
}
if !removed {
return errs.ResourceNotFoundWithScope(code.CloudEPPermission, 0, "role assignment not found")
}
return nil
}
// GetUsersForRole 獲取角色下的所有用戶
func (uc *PermissionUseCase) GetUsersForRole(ctx context.Context, roleUID string) ([]string, error) {
return uc.enforcer.GetUsersForRole(roleUID)
}
// GetRolesForUser 獲取用戶的所有角色
func (uc *PermissionUseCase) GetRolesForUser(ctx context.Context, uid string) ([]string, error) {
return uc.enforcer.GetRolesForUser(uid)
}
// AddPermissionForRole 為角色添加權限
func (uc *PermissionUseCase) AddPermissionForRole(ctx context.Context, roleUID, httpPath, httpMethod string) error {
added, err := uc.enforcer.AddPolicy(roleUID, httpPath, httpMethod)
if err != nil {
return errs.SystemInternalErrorScope(code.CloudEPPermission, "casbin add policy failed: "+err.Error())
}
if !added {
return errs.ResourceAlreadyExistWithScope(code.CloudEPPermission, "policy already exists")
}
return nil
}
// RemovePermissionForRole 移除角色的權限
func (uc *PermissionUseCase) RemovePermissionForRole(ctx context.Context, roleUID, httpPath, httpMethod string) error {
removed, err := uc.enforcer.RemovePolicy(roleUID, httpPath, httpMethod)
if err != nil {
return errs.SystemInternalErrorScope(code.CloudEPPermission, "casbin remove policy failed: "+err.Error())
}
if !removed {
return errs.ResourceNotFoundWithScope(code.CloudEPPermission, 0, "policy not found")
}
return nil
}
// GetPermissionsForRole 獲取角色的所有權限
func (uc *PermissionUseCase) GetPermissionsForRole(ctx context.Context, roleUID string) (map[string]int, error) {
policies, err := uc.enforcer.GetPermissionsForUser(roleUID)
if err != nil {
return nil, errs.SystemInternalErrorScope(code.CloudEPPermission, "casbin get permissions failed: "+err.Error())
}
permissions := make(map[string]int)
for _, policy := range policies {
if len(policy) >= 3 {
key := policy[2] + ":" + policy[1] // method:path
permissions[key] = 1
}
}
return permissions, nil
}
// CheckPatternPermission 檢查模式權限 (支援通配符)
func (uc *PermissionUseCase) CheckPatternPermission(ctx context.Context, uid, pattern, action string) (bool, error) {
hasPermission, err := uc.enforcer.Enforce(uid, pattern, action)
if err != nil {
return false, errs.SystemInternalErrorScope(code.CloudEPPermission, "casbin enforce failed: "+err.Error())
}
return hasPermission, nil
}
// GetAllPolicies 獲取所有策略
func (uc *PermissionUseCase) GetAllPolicies(ctx context.Context) ([][]string, error) {
policies, err := uc.enforcer.GetPolicy()
if err != nil {
return nil, errs.SystemInternalErrorScope(code.CloudEPPermission, "failed to get all policies: "+err.Error())
}
return policies, nil
}
// GetFilteredPolicies 獲取過濾後的策略
func (uc *PermissionUseCase) GetFilteredPolicies(ctx context.Context, fieldIndex int, fieldValues ...string) ([][]string, error) {
policies, err := uc.enforcer.GetFilteredPolicy(fieldIndex, fieldValues...)
if err != nil {
return nil, errs.SystemInternalErrorScope(code.CloudEPPermission, "failed to get filtered policies: "+err.Error())
}
return policies, nil
}