first init
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\PersonalAccessToken;
|
||||
use App\Services\ActiveRoleService;
|
||||
use App\Support\AuthCookie;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\Auth\Entities\User;
|
||||
use Modules\Auth\Transformers\UserResource;
|
||||
|
||||
class ImpersonateController extends Controller
|
||||
{
|
||||
private const IMPERSONATION_TOKEN = 'impersonation-token';
|
||||
|
||||
private const AUTH_TOKEN_NAMES = ['authToken', 'auth-token'];
|
||||
|
||||
public function take(Request $request, string $id): JsonResponse
|
||||
{
|
||||
$target = User::findOrFail($id);
|
||||
$admin = $request->user();
|
||||
|
||||
if (! $admin->can('impersonate.user', $target)) {
|
||||
return $this->error('Anda tidak mempunyai keizinan untuk menyamar pengguna.', 403);
|
||||
}
|
||||
|
||||
if ($request->hasCookie(AuthCookie::originalUserCookieName())) {
|
||||
return $this->error('Anda sudah menyamar sebagai pengguna.', 400);
|
||||
}
|
||||
|
||||
$issued = $this->issueToken($target, self::IMPERSONATION_TOKEN);
|
||||
|
||||
return AuthCookie::attachAuthToken(
|
||||
response()->json([
|
||||
'success' => true,
|
||||
'message' => "Anda sekarang menyamar sebagai {$target->name}",
|
||||
'impersonated_user' => $this->userSummary($target),
|
||||
...$this->sessionPayload($target, $issued['accessToken']),
|
||||
]),
|
||||
$issued['plainTextToken']
|
||||
)->withCookie(AuthCookie::makeOriginalUserId($admin->id));
|
||||
}
|
||||
|
||||
public function leave(Request $request): JsonResponse
|
||||
{
|
||||
$originalUserId = $request->cookie(AuthCookie::originalUserCookieName());
|
||||
|
||||
if (! $originalUserId) {
|
||||
return $this->error('Maklumat pengguna asal tidak ditemui.', 400);
|
||||
}
|
||||
|
||||
$original = User::findOrFail($originalUserId);
|
||||
|
||||
$request->user()?->tokens()->where('name', self::IMPERSONATION_TOKEN)->delete();
|
||||
$original->tokens()->whereIn('name', [self::IMPERSONATION_TOKEN, ...self::AUTH_TOKEN_NAMES])->delete();
|
||||
|
||||
$issued = $this->issueToken($original, 'auth-token', expires: true);
|
||||
|
||||
$response = response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Anda telah kembali ke akaun anda',
|
||||
'original_user' => $this->userSummary($original),
|
||||
...$this->sessionPayload($original, $issued['accessToken']),
|
||||
]);
|
||||
|
||||
if (AuthCookie::shouldExposeTokenInResponse()) {
|
||||
$response->setData(array_merge($response->getData(true), [
|
||||
'original_token' => $issued['plainTextToken'],
|
||||
]));
|
||||
}
|
||||
|
||||
return AuthCookie::attachAuthToken($response, $issued['plainTextToken'])
|
||||
->withCookie(AuthCookie::forgetOriginalUserId());
|
||||
}
|
||||
|
||||
public function status(Request $request): JsonResponse
|
||||
{
|
||||
if (! $request->hasCookie(AuthCookie::originalUserCookieName())) {
|
||||
return response()->json(['is_impersonating' => false]);
|
||||
}
|
||||
|
||||
$user = $request->user();
|
||||
|
||||
return response()->json([
|
||||
'is_impersonating' => true,
|
||||
'impersonated_user' => $user ? $this->userSummary($user) : null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{plainTextToken: string, accessToken: PersonalAccessToken}
|
||||
*/
|
||||
private function issueToken(User $user, string $name, bool $expires = false): array
|
||||
{
|
||||
$user->loadMissing(['roles.permissions']);
|
||||
|
||||
$result = $user->createToken(
|
||||
$name,
|
||||
['*'],
|
||||
$expires ? now()->addMinutes((int) config('auth_cookie.lifetime_minutes', 720)) : null
|
||||
);
|
||||
|
||||
ActiveRoleService::assignDefaultToToken($user, $result->accessToken);
|
||||
|
||||
return [
|
||||
'plainTextToken' => $result->plainTextToken,
|
||||
'accessToken' => $result->accessToken,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function sessionPayload(User $user, PersonalAccessToken $accessToken): array
|
||||
{
|
||||
$user->loadMissing(['roles.permissions']);
|
||||
|
||||
$activeRole = $user->roles->firstWhere('id', $accessToken->active_role_id)
|
||||
?? ActiveRoleService::resolveDefaultRole($user);
|
||||
|
||||
return [
|
||||
'data' => new UserResource($user),
|
||||
'active_role' => ActiveRoleService::formatRole($activeRole),
|
||||
'can_switch_role' => $user->roles->count() > 1,
|
||||
'redirect_path' => $activeRole
|
||||
? ActiveRoleService::redirectPathForRole($activeRole)
|
||||
: config('active_role.member_redirect', '/profile'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{id: mixed, name: string, email: string}
|
||||
*/
|
||||
private function userSummary(User $user): array
|
||||
{
|
||||
return [
|
||||
'id' => $user->id,
|
||||
'name' => $user->name,
|
||||
'email' => $user->email,
|
||||
];
|
||||
}
|
||||
|
||||
private function error(string $message, int $status): JsonResponse
|
||||
{
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => $message,
|
||||
], $status);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user