권한 관련 문제
권한 시스템 (Level 0~6, ADR-058) 사용 시 발생할 수 있는 문제와 해결 방법입니다.
403 Forbidden 오류
권한 레벨 부족
증상:
{
"success": false,
"message": "권한이 부족합니다.",
"error": {
"code": "forbidden",
"required_level": 2,
"current_level": 6
}
}
원인:
- 현재 사용자 권한이 요청된 작업에 부족
해결 방법:
-
현재 권한 확인
// Tinker에서
auth()->user()->permission_level;
// 결과: 6 (Member) -
필요 권한 확인
// 해당 리소스의 Policy 확인
// app/Policies/UserPolicy.php
public function update(User $user, User $model)
{
return $user->permission_level <= $model->permission_level;
} -
권한 상승 요청
- 상위 관리자에게 권한 변경 요청
범위(Scope) 제한
증상:
{
"success": false,
"message": "접근할 수 없는 리소스입니다."
}
원인:
- 다른 테넌트/조직/팀의 리소스 접근 시도
확인 방법:
// 현재 사용자의 접근 범위
$user = auth()->user();
echo "Tenant: {$user->tenant_id}";
echo "Organization: {$user->organization_id}";
echo "Team: {$user->team_id}";
// 요청된 리소스의 소속
$resource = User::find($targetId);
echo "Target Tenant: {$resource->tenant_id}";
권한 레벨별 범위:
| Level | 접근 가능 범위 |
|---|---|
| 0-1 | 모든 테넌트 |
| 2 | 자기 테넌트 내 모든 데이터 |
| 3 | 자기 조직 내 모든 데이터 |
| 4 | 자기 워크스페이스 내 데이터 |
| 5 | 자기 팀 내 데이터 |
| 6 | 자기 데이터만 |
권한이 적용되지 않음
Policy 미등록
증상:
- 권한 검사가 작동하지 않음
- 모든 사용자가 접근 가능
확인 방법:
// app/Providers/AuthServiceProvider.php
protected $policies = [
User::class => UserPolicy::class, // 등록 확인
];
해결 방법:
// AuthServiceProvider.php에 추가
protected $policies = [
\App\Models\User::class => \App\Policies\UserPolicy::class,
\App\Models\Organization::class => \App\Policies\OrganizationPolicy::class,
];
Gate/Policy 미적용
증상:
- Controller에서 권한 검사 누락
확인 방법:
// Controller 메서드 확인
public function update(Request $request, User $user)
{
// ❌ 권한 검사 없음
$user->update($request->all());
}
해결 방법:
public function update(Request $request, User $user)
{
// ✅ authorize 추가
$this->authorize('update', $user);
$user->update($request->validated());
}
미들웨어 누락
증상:
- 인증 없이 접근 가능
확인 방법:
// routes/api.php
Route::get('/users', [UserController::class, 'index']); // ❌ 미들웨어 없음
해결 방법:
Route::middleware(['auth:sanctum', 'tenant'])->group(function () {
Route::get('/users', [UserController::class, 'index']); // ✅
});
권한 상속 문제
상위 권한이 적용 안 됨
증상:
- Tenant Admin(Level 2)인데 Organization Admin(Level 3) 작업 불가
원인:
- 권한 비교 로직 오류
확인 방법:
// 올바른 비교 (숫자가 작을수록 상위)
if ($user->permission_level <= $requiredLevel) {
// 권한 있음
}
// ❌ 잘못된 비교
if ($user->permission_level >= $requiredLevel) {
// 로직 오류
}
레벨 구조:
Level 0 (가장 높음) → Platform Admin
Level 1 → SaaS Admin
Level 2 → Tenant Admin
Level 3 → Organization Admin
Level 4 → Workspace Admin
Level 5 → Team Leader
Level 6 (가장 낮음) → Member
자신보다 높은 권한 부여 시도
증상:
{
"success": false,
"message": "자신보다 높은 권한을 부여할 수 없습니다."
}
원인:
- 권한 에스컬레이션 방지 로직
확인:
// 권한 변경 검증
if ($newLevel < auth()->user()->permission_level) {
throw new AuthorizationException(
'자신보다 높은 권한을 부여할 수 없습니다.'
);
}
해결 방법:
- 상위 관리자에게 권한 변경 요청
- 또는 Platform Admin(Level 0)이 처리
캐시 관련 문제
권한 변경 후 미반영
증상:
- 권한 변경 후에도 이전 권한으로 동작
원인:
- 권한 정보 캐싱
해결 방법:
-
캐시 정리
php artisan cache:clear -
사용자 재로그인
- 세션/토큰 갱신 필요
-
캐시 키 확인
// 권한 캐시 삭제
Cache::forget("user:{$userId}:permissions");
토큰 재발급 필요
증상:
- API 토큰에 이전 권한 정보 포함
해결 방법:
// 기존 토큰 삭제 후 재발급
$user->tokens()->delete();
$newToken = $user->createToken('api-token')->plainTextToken;
테넌트 격리 문제
다른 테넌트 데이터 접근
증상:
- 다른 테넌트의 데이터가 조회됨 (보안 문제!)
원인:
- TenantScope 미적용
- 직접 쿼리로 우회
확인 방법:
// Model에 Scope 확인
class User extends Model
{
use BelongsToTenant; // 이 trait 필수
}
해결 방법:
// ❌ 직접 쿼리 (Scope 우회)
DB::table('users')->where('id', 1)->first();
// ✅ Eloquent 사용 (Scope 자동 적용)
User::find(1);
테넌트 컨텍스트 미설정
증상:
- 테넌트 관련 쿼리에서 빈 결과
확인 방법:
// 현재 테넌트 확인
dd(tenant()); // null이면 미설정
해결 방법:
// 미들웨어 확인
Route::middleware(['auth:sanctum', 'tenant'])->group(...);
// 또는 수동 설정
tenancy()->initialize(Tenant::find(1));
디버깅 방법
권한 로그 활성화
// config/logging.php channels에 추가
'permission' => [
'driver' => 'daily',
'path' => storage_path('logs/permission.log'),
'level' => 'debug',
],
// 사용
Log::channel('permission')->debug('Permission check', [
'user_id' => auth()->id(),
'action' => 'update',
'resource' => User::class,
'resource_id' => $id,
]);
Tinker로 권한 테스트
php artisan tinker
$user = User::find(1);
$targetUser = User::find(2);
// 권한 검사
Gate::forUser($user)->allows('update', $targetUser); // true/false
// 권한 레벨 확인
$user->permission_level; // 0-6
// 수행 가능 작업
$user->can('update', $targetUser);
$user->cannot('delete', $targetUser);
요청 로그 확인
// Middleware에서 로깅
public function handle($request, Closure $next)
{
Log::debug('Permission Middleware', [
'user' => auth()->id(),
'level' => auth()->user()?->permission_level,
'path' => $request->path(),
'method' => $request->method(),
]);
return $next($request);
}
일반적인 실수
1. Gate와 Policy 혼용 오류
// ❌ 잘못된 사용
Gate::allows('update', [$user, $post]); // Policy 형식으로 호출
// ✅ 올바른 사용
$user->can('update', $post); // Policy
Gate::allows('admin-only'); // Gate
2. 권한 비교 방향 오류
// ❌ 잘못됨 (Level 0이 가장 높음을 잊음)
if ($user->permission_level >= 2) {
// Tenant Admin 이상...
}
// ✅ 올바름
if ($user->permission_level <= 2) {
// Tenant Admin(2) 이상 (0, 1, 2)
}
3. 자기 참조 수정
// ❌ 자기 권한 변경 허용
$user->update(['permission_level' => 0]);
// ✅ 자기 권한 변경 방지
if ($user->id === auth()->id()) {
throw new AuthorizationException('본인 권한은 변경할 수 없습니다.');
}
권한 초기화 (긴급 복구)
주의
운영 환경에서는 신중하게 사용하세요.
# Platform Admin 계정 생성/복구
php artisan tinker
$admin = User::updateOrCreate(
['email' => 'admin@example.com'],
[
'name' => 'Platform Admin',
'password' => bcrypt('secure-password'),
'permission_level' => 0,
]
);