250 lines
6.1 KiB
Go
250 lines
6.1 KiB
Go
package usecase
|
|
|
|
import (
|
|
"context"
|
|
"permission/reborn/config"
|
|
"permission/reborn/domain/entity"
|
|
"permission/reborn/domain/errors"
|
|
"permission/reborn/domain/repository"
|
|
"permission/reborn/domain/usecase"
|
|
)
|
|
|
|
type rolePermissionUseCase struct {
|
|
permRepo repository.PermissionRepository
|
|
rolePermRepo repository.RolePermissionRepository
|
|
roleRepo repository.RoleRepository
|
|
userRoleRepo repository.UserRoleRepository
|
|
permUseCase usecase.PermissionUseCase
|
|
cache repository.CacheRepository
|
|
config config.RoleConfig
|
|
}
|
|
|
|
// NewRolePermissionUseCase 建立角色權限 UseCase
|
|
func NewRolePermissionUseCase(
|
|
permRepo repository.PermissionRepository,
|
|
rolePermRepo repository.RolePermissionRepository,
|
|
roleRepo repository.RoleRepository,
|
|
userRoleRepo repository.UserRoleRepository,
|
|
permUseCase usecase.PermissionUseCase,
|
|
cache repository.CacheRepository,
|
|
cfg config.RoleConfig,
|
|
) usecase.RolePermissionUseCase {
|
|
return &rolePermissionUseCase{
|
|
permRepo: permRepo,
|
|
rolePermRepo: rolePermRepo,
|
|
roleRepo: roleRepo,
|
|
userRoleRepo: userRoleRepo,
|
|
permUseCase: permUseCase,
|
|
cache: cache,
|
|
config: cfg,
|
|
}
|
|
}
|
|
|
|
func (uc *rolePermissionUseCase) GetByRoleUID(ctx context.Context, roleUID string) (entity.Permissions, error) {
|
|
// 檢查是否為管理員
|
|
if roleUID == uc.config.AdminRoleUID {
|
|
return uc.getAllPermissions(ctx)
|
|
}
|
|
|
|
// 嘗試從快取取得
|
|
if uc.cache != nil {
|
|
var permissions entity.Permissions
|
|
cacheKey := repository.CacheKeyRolePermission(roleUID)
|
|
err := uc.cache.GetObject(ctx, cacheKey, &permissions)
|
|
if err == nil && len(permissions) > 0 {
|
|
return permissions, nil
|
|
}
|
|
}
|
|
|
|
// 取得角色
|
|
role, err := uc.roleRepo.GetByUID(ctx, roleUID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// 取得角色權限關聯
|
|
rolePerms, err := uc.rolePermRepo.GetByRoleID(ctx, role.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(rolePerms) == 0 {
|
|
return make(entity.Permissions), nil
|
|
}
|
|
|
|
// 取得權限樹並建立權限集合
|
|
perms, err := uc.permRepo.ListActive(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
tree := NewPermissionTree(perms)
|
|
|
|
// 取得權限 ID 列表
|
|
permIDs := make([]int64, len(rolePerms))
|
|
for i, rp := range rolePerms {
|
|
permIDs[i] = rp.PermissionID
|
|
}
|
|
|
|
// 建立權限集合 (包含父權限)
|
|
permissions := tree.BuildPermissionsFromIDs(permIDs)
|
|
|
|
// 存入快取
|
|
if uc.cache != nil {
|
|
cacheKey := repository.CacheKeyRolePermission(roleUID)
|
|
_ = uc.cache.SetObject(ctx, cacheKey, permissions, 0)
|
|
}
|
|
|
|
return permissions, nil
|
|
}
|
|
|
|
func (uc *rolePermissionUseCase) GetByUserUID(ctx context.Context, userUID string) (*usecase.UserPermissionResponse, error) {
|
|
// 嘗試從快取取得
|
|
if uc.cache != nil {
|
|
var resp usecase.UserPermissionResponse
|
|
cacheKey := repository.CacheKeyUserPermission(userUID)
|
|
err := uc.cache.GetObject(ctx, cacheKey, &resp)
|
|
if err == nil && resp.RoleUID != "" {
|
|
return &resp, nil
|
|
}
|
|
}
|
|
|
|
// 取得使用者角色
|
|
userRole, err := uc.userRoleRepo.Get(ctx, userUID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// 取得角色
|
|
role, err := uc.roleRepo.GetByUID(ctx, userRole.RoleID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// 取得角色權限
|
|
permissions, err := uc.GetByRoleUID(ctx, userRole.RoleID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
resp := &usecase.UserPermissionResponse{
|
|
UserUID: userUID,
|
|
RoleUID: role.UID,
|
|
RoleName: role.Name,
|
|
Permissions: permissions,
|
|
}
|
|
|
|
// 存入快取
|
|
if uc.cache != nil {
|
|
cacheKey := repository.CacheKeyUserPermission(userUID)
|
|
_ = uc.cache.SetObject(ctx, cacheKey, resp, 0)
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func (uc *rolePermissionUseCase) UpdateRolePermissions(ctx context.Context, roleUID string, permissions entity.Permissions) error {
|
|
// 取得角色
|
|
role, err := uc.roleRepo.GetByUID(ctx, roleUID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// 展開權限 (包含父權限)
|
|
expandedPerms, err := uc.permUseCase.ExpandPermissions(ctx, permissions)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// 取得權限樹並轉換為 ID
|
|
perms, err := uc.permRepo.ListActive(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
tree := NewPermissionTree(perms)
|
|
permIDs, err := tree.GetPermissionIDs(expandedPerms)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// 更新角色權限
|
|
if err := uc.rolePermRepo.Update(ctx, role.ID, permIDs); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 清除快取
|
|
if uc.cache != nil {
|
|
// 清除角色權限快取
|
|
_ = uc.cache.Delete(ctx, repository.CacheKeyRolePermission(roleUID))
|
|
|
|
// 清除所有使用此角色的使用者權限快取
|
|
userRoles, _ := uc.userRoleRepo.GetByRoleID(ctx, roleUID)
|
|
for _, ur := range userRoles {
|
|
_ = uc.cache.Delete(ctx, repository.CacheKeyUserPermission(ur.UID))
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (uc *rolePermissionUseCase) CheckPermission(ctx context.Context, roleUID, path, method string) (*usecase.PermissionCheckResponse, error) {
|
|
// 檢查是否為管理員
|
|
if roleUID == uc.config.AdminRoleUID {
|
|
return &usecase.PermissionCheckResponse{
|
|
Allowed: true,
|
|
PlainCode: true,
|
|
}, nil
|
|
}
|
|
|
|
// 取得角色權限
|
|
permissions, err := uc.GetByRoleUID(ctx, roleUID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// 取得 API 權限
|
|
perm, err := uc.permRepo.GetByHTTP(ctx, path, method)
|
|
if err != nil {
|
|
if errors.Is(err, errors.ErrPermissionNotFound) {
|
|
// 如果找不到對應的權限定義,預設拒絕
|
|
return &usecase.PermissionCheckResponse{
|
|
Allowed: false,
|
|
}, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
// 檢查是否有權限
|
|
allowed := permissions.HasPermission(perm.Name)
|
|
|
|
resp := &usecase.PermissionCheckResponse{
|
|
Allowed: allowed,
|
|
PermissionName: perm.Name,
|
|
PlainCode: false,
|
|
}
|
|
|
|
// 檢查是否有 plain_code 權限 (特殊邏輯)
|
|
if allowed && method == "GET" {
|
|
plainCodePermName := perm.Name + ".plain_code"
|
|
resp.PlainCode = permissions.HasPermission(plainCodePermName)
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
// getAllPermissions 取得所有權限 (管理員用)
|
|
func (uc *rolePermissionUseCase) getAllPermissions(ctx context.Context) (entity.Permissions, error) {
|
|
perms, err := uc.permRepo.ListActive(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
permissions := make(entity.Permissions)
|
|
for _, perm := range perms {
|
|
permissions.AddPermission(perm.Name)
|
|
}
|
|
|
|
return permissions, nil
|
|
}
|