refactor: [authz] 역할/권한 API 품질 개선
- Validator::make를 FormRequest로 분리 (6개 생성) - 하드코딩 한글 문자열을 i18n 키로 교체 - RoleMenuPermission 데드코드 제거 - Role 모델 SpatieRole 상속으로 일원화 - 권한 변경 후 캐시 무효화 추가 (AccessService::bumpVersion) - 미문서화 8개 Swagger 엔드포인트 추가 - 역할/권한 라우트에 perm.map+permission 미들웨어 추가
This commit is contained in:
@@ -3,8 +3,7 @@
|
||||
namespace App\Services\Authz;
|
||||
|
||||
use App\Models\Members\User;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use App\Models\Permissions\Role;
|
||||
use Spatie\Permission\PermissionRegistrar;
|
||||
|
||||
class UserRoleService
|
||||
@@ -17,6 +16,13 @@ protected static function setTeam(int $tenantId): void
|
||||
app(PermissionRegistrar::class)->setPermissionsTeamId($tenantId);
|
||||
}
|
||||
|
||||
/** 권한 캐시 무효화 */
|
||||
protected static function invalidateCache(int $tenantId): void
|
||||
{
|
||||
AccessService::bumpVersion($tenantId);
|
||||
app(PermissionRegistrar::class)->forgetCachedPermissions();
|
||||
}
|
||||
|
||||
/** 유저 로드 (존재 체크) */
|
||||
protected static function loadUserOrError(int $userId): ?User
|
||||
{
|
||||
@@ -54,14 +60,13 @@ protected static function resolveRoleNames(int $tenantId, array $params): array
|
||||
// 정제
|
||||
$names = array_values(array_unique(array_filter($names)));
|
||||
|
||||
// 존재 확인(필요시 에러 처리 확장 가능)
|
||||
// 존재 확인
|
||||
if (! empty($names)) {
|
||||
$count = Role::query()
|
||||
Role::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('guard_name', self::$guard)
|
||||
->whereIn('name', $names)
|
||||
->count();
|
||||
// if ($count !== count($names)) { ... 필요시 상세 에러 반환 }
|
||||
}
|
||||
|
||||
return $names;
|
||||
@@ -74,12 +79,11 @@ public static function list(int $userId)
|
||||
|
||||
$user = self::loadUserOrError($userId);
|
||||
if (! $user) {
|
||||
return ['error' => '사용자를 찾을 수 없습니다.', 'code' => 404];
|
||||
return ['error' => __('error.role.user_not_found'), 'code' => 404];
|
||||
}
|
||||
|
||||
self::setTeam($tenantId);
|
||||
|
||||
// 현재 테넌트의 역할만
|
||||
$builder = $user->roles()
|
||||
->where('roles.tenant_id', $tenantId)
|
||||
->where('roles.guard_name', self::$guard)
|
||||
@@ -96,30 +100,19 @@ public static function grant(int $userId, array $params = [])
|
||||
|
||||
$user = self::loadUserOrError($userId);
|
||||
if (! $user) {
|
||||
return ['error' => '사용자를 찾을 수 없습니다.', 'code' => 404];
|
||||
}
|
||||
|
||||
$v = Validator::make($params, [
|
||||
'role_names' => 'sometimes|array',
|
||||
'role_names.*' => 'string|min:1',
|
||||
'role_ids' => 'sometimes|array',
|
||||
'role_ids.*' => 'integer|min:1',
|
||||
]);
|
||||
if ($v->fails()) {
|
||||
return ['error' => $v->errors()->first(), 'code' => 422];
|
||||
}
|
||||
if (empty($params['role_names']) && empty($params['role_ids'])) {
|
||||
return ['error' => 'role_names 또는 role_ids 중 하나는 필요합니다.', 'code' => 422];
|
||||
return ['error' => __('error.role.user_not_found'), 'code' => 404];
|
||||
}
|
||||
|
||||
self::setTeam($tenantId);
|
||||
|
||||
$names = self::resolveRoleNames($tenantId, $params);
|
||||
if (empty($names)) {
|
||||
return ['error' => '유효한 역할이 없습니다.', 'code' => 422];
|
||||
return ['error' => __('error.role.no_valid_roles'), 'code' => 422];
|
||||
}
|
||||
|
||||
$user->assignRole($names); // teams 컨텍스트 적용됨
|
||||
$user->assignRole($names);
|
||||
|
||||
self::invalidateCache($tenantId);
|
||||
|
||||
return 'success';
|
||||
}
|
||||
@@ -131,30 +124,19 @@ public static function revoke(int $userId, array $params = [])
|
||||
|
||||
$user = self::loadUserOrError($userId);
|
||||
if (! $user) {
|
||||
return ['error' => '사용자를 찾을 수 없습니다.', 'code' => 404];
|
||||
}
|
||||
|
||||
$v = Validator::make($params, [
|
||||
'role_names' => 'sometimes|array',
|
||||
'role_names.*' => 'string|min:1',
|
||||
'role_ids' => 'sometimes|array',
|
||||
'role_ids.*' => 'integer|min:1',
|
||||
]);
|
||||
if ($v->fails()) {
|
||||
return ['error' => $v->errors()->first(), 'code' => 422];
|
||||
}
|
||||
if (empty($params['role_names']) && empty($params['role_ids'])) {
|
||||
return ['error' => 'role_names 또는 role_ids 중 하나는 필요합니다.', 'code' => 422];
|
||||
return ['error' => __('error.role.user_not_found'), 'code' => 404];
|
||||
}
|
||||
|
||||
self::setTeam($tenantId);
|
||||
|
||||
$names = self::resolveRoleNames($tenantId, $params);
|
||||
if (empty($names)) {
|
||||
return ['error' => '유효한 역할이 없습니다.', 'code' => 422];
|
||||
return ['error' => __('error.role.no_valid_roles'), 'code' => 422];
|
||||
}
|
||||
|
||||
$user->removeRole($names); // 배열 허용
|
||||
$user->removeRole($names);
|
||||
|
||||
self::invalidateCache($tenantId);
|
||||
|
||||
return 'success';
|
||||
}
|
||||
@@ -166,32 +148,20 @@ public static function sync(int $userId, array $params = [])
|
||||
|
||||
$user = self::loadUserOrError($userId);
|
||||
if (! $user) {
|
||||
return ['error' => '사용자를 찾을 수 없습니다.', 'code' => 404];
|
||||
}
|
||||
|
||||
$v = Validator::make($params, [
|
||||
'role_names' => 'sometimes|array',
|
||||
'role_names.*' => 'string|min:1',
|
||||
'role_ids' => 'sometimes|array',
|
||||
'role_ids.*' => 'integer|min:1',
|
||||
]);
|
||||
if ($v->fails()) {
|
||||
return ['error' => $v->errors()->first(), 'code' => 422];
|
||||
}
|
||||
if (empty($params['role_names']) && empty($params['role_ids'])) {
|
||||
return ['error' => 'role_names 또는 role_ids 중 하나는 필요합니다.', 'code' => 422];
|
||||
return ['error' => __('error.role.user_not_found'), 'code' => 404];
|
||||
}
|
||||
|
||||
self::setTeam($tenantId);
|
||||
|
||||
$names = self::resolveRoleNames($tenantId, $params);
|
||||
if (empty($names)) {
|
||||
// 정책상 빈 목록 sync 허용 시: $user->syncRoles([]) 로 전부 제거 가능
|
||||
return ['error' => '유효한 역할이 없습니다.', 'code' => 422];
|
||||
return ['error' => __('error.role.no_valid_roles'), 'code' => 422];
|
||||
}
|
||||
|
||||
$user->syncRoles($names);
|
||||
|
||||
self::invalidateCache($tenantId);
|
||||
|
||||
return 'success';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user