- add rotating admin refresh tokens and password gates\n- expand ticket galleries, exports, and client resources\n- improve IP allocation auditing and dashboard data\n- enforce encrypted client access tokens on public routes
69 lines
2.0 KiB
PHP
69 lines
2.0 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Api\Admin;
|
|
|
|
use App\Models\AdminRefreshToken;
|
|
use Carbon\CarbonInterface;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Validation\ValidationException;
|
|
use Tymon\JWTAuth\Facades\JWTAuth;
|
|
|
|
class AdminRefreshTokenService
|
|
{
|
|
public function create(int $userId, CarbonInterface $expiresAt): string
|
|
{
|
|
$rawToken = Str::random(64);
|
|
|
|
AdminRefreshToken::create([
|
|
'user_id' => $userId,
|
|
'token' => hash('sha256', $rawToken),
|
|
'expires_at' => $expiresAt,
|
|
]);
|
|
|
|
return $rawToken;
|
|
}
|
|
|
|
public function rotate(string $rawToken): array
|
|
{
|
|
return DB::transaction(function () use ($rawToken): array {
|
|
$record = AdminRefreshToken::where('token', hash('sha256', $rawToken))
|
|
->lockForUpdate()
|
|
->first();
|
|
|
|
if (! $record || $record->expires_at->isPast()) {
|
|
$record?->delete();
|
|
|
|
throw ValidationException::withMessages([
|
|
'refresh_token' => ['Refresh token không hợp lệ hoặc đã hết hạn.'],
|
|
]);
|
|
}
|
|
|
|
$user = $record->user;
|
|
if (! $user) {
|
|
$record->delete();
|
|
|
|
throw ValidationException::withMessages([
|
|
'refresh_token' => ['Tài khoản không hợp lệ.'],
|
|
]);
|
|
}
|
|
|
|
$expiresAt = $record->expires_at->copy();
|
|
$record->delete();
|
|
$newRefreshToken = $this->create($user->id, $expiresAt);
|
|
|
|
return [
|
|
'user' => $user,
|
|
'token' => JWTAuth::fromUser($user),
|
|
'refresh_token' => $newRefreshToken,
|
|
'refresh_expires_in' => (int) max(0, now()->diffInSeconds($expiresAt, false)),
|
|
];
|
|
});
|
|
}
|
|
|
|
public function revoke(string $rawToken): void
|
|
{
|
|
AdminRefreshToken::where('token', hash('sha256', $rawToken))->delete();
|
|
}
|
|
}
|