feat: 로그인 응답에 사용자/테넌트/메뉴 정보 추가
- MemberService::getUserInfoForLogin() 메서드 추가
- 사용자 기본 정보 (id, user_id, name, email, phone)
- 활성 테넌트 정보 (is_default 우선 → is_active 차순)
- 테넌트 없는 경우 null 반환
- 추가 테넌트 목록 (other_tenants 배열)
- 권한 기반 메뉴 필터링 (menu:{id}.view)
- 권한 체크 3단계
- 기본 Role 권한 (model_has_permissions)
- Override 권한 (permission_overrides, 시간 제약)
- 우선순위: deny(-1) > allow(1) > base permission
- ApiController::login() 응답 구조 변경
- 기존: {message, user_token}
- 개선: {message, user_token, user, tenant, menus}
- Swagger 문서 업데이트 (AuthApi.php)
- 테넌트 있는 경우 응답 스키마
- 테넌트 없는 경우 응답 스키마 (null)
- 에러 케이스 추가 (400, 401, 404)
This commit is contained in:
@@ -2,9 +2,11 @@
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Commons\Menu;
|
||||
use App\Models\Members\User;
|
||||
use App\Models\Members\UserTenant;
|
||||
use App\Models\Tenants\Tenant;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class MemberService
|
||||
@@ -177,4 +179,134 @@ public static function switchMyTenant(int $tenantId)
|
||||
|
||||
return 'success';
|
||||
}
|
||||
|
||||
/**
|
||||
* 로그인 사용자 정보 조회 (테넌트 + 메뉴 권한 포함)
|
||||
*/
|
||||
public static function getUserInfoForLogin(int $userId): array
|
||||
{
|
||||
// 1. 사용자 기본 정보 조회
|
||||
$user = User::find($userId);
|
||||
if (! $user) {
|
||||
throw new \Exception('사용자를 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
// 기본 사용자 정보 (민감 정보 제외)
|
||||
$userInfo = [
|
||||
'id' => $user->id,
|
||||
'user_id' => $user->user_id,
|
||||
'name' => $user->name,
|
||||
'email' => $user->email,
|
||||
'phone' => $user->phone,
|
||||
];
|
||||
|
||||
// 2. 활성 테넌트 조회 (1순위: is_default=1, 2순위: is_active=1 첫 번째)
|
||||
$userTenants = UserTenant::with('tenant')
|
||||
->where('user_id', $userId)
|
||||
->where('is_active', 1)
|
||||
->orderByDesc('is_default')
|
||||
->orderBy('id')
|
||||
->get();
|
||||
|
||||
if ($userTenants->isEmpty()) {
|
||||
return [
|
||||
'user' => $userInfo,
|
||||
'tenant' => null,
|
||||
'menus' => [],
|
||||
];
|
||||
}
|
||||
|
||||
$defaultUserTenant = $userTenants->first();
|
||||
$tenant = $defaultUserTenant->tenant;
|
||||
|
||||
// 3. 테넌트 정보 구성
|
||||
$tenantInfo = [
|
||||
'id' => $tenant->id,
|
||||
'company_name' => $tenant->company_name,
|
||||
'business_num' => $tenant->business_num,
|
||||
'tenant_st_code' => $tenant->tenant_st_code,
|
||||
'other_tenants' => $userTenants->skip(1)->map(function ($ut) {
|
||||
return [
|
||||
'tenant_id' => $ut->tenant_id,
|
||||
'company_name' => $ut->tenant->company_name,
|
||||
'business_num' => $ut->tenant->business_num,
|
||||
'tenant_st_code' => $ut->tenant->tenant_st_code,
|
||||
];
|
||||
})->values()->toArray(),
|
||||
];
|
||||
|
||||
// 4. 메뉴 권한 체크 (menu:{menu_id}.view 패턴)
|
||||
// 4-1. 기본 Role 권한 (model_has_permissions)
|
||||
$rolePermissions = DB::table('model_has_permissions')
|
||||
->join('permissions', 'model_has_permissions.permission_id', '=', 'permissions.id')
|
||||
->where('model_has_permissions.model_type', User::class)
|
||||
->where('model_has_permissions.model_id', $userId)
|
||||
->where('model_has_permissions.tenant_id', $tenant->id)
|
||||
->where('permissions.name', 'like', 'menu:%.view')
|
||||
->pluck('permissions.name')
|
||||
->toArray();
|
||||
|
||||
// 4-2. Override 권한 (명시적 허용/차단)
|
||||
$overrides = DB::table('permission_overrides')
|
||||
->join('permissions', 'permission_overrides.permission_id', '=', 'permissions.id')
|
||||
->where('permission_overrides.tenant_id', $tenant->id)
|
||||
->where('permission_overrides.model_type', User::class)
|
||||
->where('permission_overrides.model_id', $userId)
|
||||
->where('permissions.name', 'like', 'menu:%.view')
|
||||
->where(function ($q) {
|
||||
$q->whereNull('permission_overrides.effective_from')
|
||||
->orWhere('permission_overrides.effective_from', '<=', now());
|
||||
})
|
||||
->where(function ($q) {
|
||||
$q->whereNull('permission_overrides.effective_to')
|
||||
->orWhere('permission_overrides.effective_to', '>=', now());
|
||||
})
|
||||
->select('permissions.name', 'permission_overrides.effect')
|
||||
->get()
|
||||
->keyBy('name');
|
||||
|
||||
// 4-3. 최종 권한 계산: (기본 || override allow) && !override deny
|
||||
$allowedMenuIds = [];
|
||||
$allMenuPermissions = array_unique(array_merge(
|
||||
$rolePermissions,
|
||||
$overrides->keys()->toArray()
|
||||
));
|
||||
|
||||
foreach ($allMenuPermissions as $permName) {
|
||||
if (preg_match('/^menu:(\d+)\.view$/', $permName, $matches)) {
|
||||
$menuId = (int) $matches[1];
|
||||
|
||||
// Override deny 체크
|
||||
if (isset($overrides[$permName]) && $overrides[$permName]->effect === -1) {
|
||||
continue; // 강제 차단
|
||||
}
|
||||
|
||||
// Override allow 또는 기본 Role 권한
|
||||
if (
|
||||
(isset($overrides[$permName]) && $overrides[$permName]->effect === 1) ||
|
||||
in_array($permName, $rolePermissions, true)
|
||||
) {
|
||||
$allowedMenuIds[] = $menuId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 메뉴 목록 조회 (권한 있는 메뉴만)
|
||||
$menus = [];
|
||||
if (! empty($allowedMenuIds)) {
|
||||
$menus = Menu::where('tenant_id', $tenant->id)
|
||||
->where('is_active', 1)
|
||||
->whereIn('id', $allowedMenuIds)
|
||||
->orderBy('parent_id')
|
||||
->orderBy('sort_order')
|
||||
->get(['id', 'parent_id', 'name', 'url', 'icon', 'sort_order'])
|
||||
->toArray();
|
||||
}
|
||||
|
||||
return [
|
||||
'user' => $userInfo,
|
||||
'tenant' => $tenantInfo,
|
||||
'menus' => $menus,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user