Refactoring, regression testing until Phase 1 end.
This commit is contained in:
@@ -4,10 +4,10 @@ namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use App\Services\JwtService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
/**
|
||||
@@ -17,6 +17,19 @@ use Illuminate\Support\Facades\Validator;
|
||||
*/
|
||||
class AuthController extends Controller
|
||||
{
|
||||
/**
|
||||
* JWT Service instance
|
||||
*/
|
||||
protected JwtService $jwtService;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct(JwtService $jwtService)
|
||||
{
|
||||
$this->jwtService = $jwtService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login and get tokens
|
||||
*
|
||||
@@ -50,6 +63,7 @@ class AuthController extends Controller
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed',
|
||||
'errors' => $validator->errors(),
|
||||
], 422);
|
||||
}
|
||||
@@ -68,14 +82,14 @@ class AuthController extends Controller
|
||||
], 403);
|
||||
}
|
||||
|
||||
$accessToken = $this->generateAccessToken($user);
|
||||
$refreshToken = $this->generateRefreshToken($user);
|
||||
$accessToken = $this->jwtService->generateAccessToken($user);
|
||||
$refreshToken = $this->jwtService->generateRefreshToken($user);
|
||||
|
||||
return response()->json([
|
||||
'access_token' => $accessToken,
|
||||
'refresh_token' => $refreshToken,
|
||||
'token_type' => 'bearer',
|
||||
'expires_in' => 3600,
|
||||
'expires_in' => $this->jwtService->getAccessTokenTTL(),
|
||||
'user' => [
|
||||
'id' => $user->id,
|
||||
'name' => $user->name,
|
||||
@@ -105,7 +119,13 @@ class AuthController extends Controller
|
||||
{
|
||||
$refreshToken = $request->input('refresh_token');
|
||||
|
||||
$userId = $this->getUserIdFromRefreshToken($refreshToken);
|
||||
if (empty($refreshToken)) {
|
||||
return response()->json([
|
||||
'message' => 'Refresh token is required',
|
||||
], 422);
|
||||
}
|
||||
|
||||
$userId = $this->jwtService->getUserIdFromRefreshToken($refreshToken);
|
||||
|
||||
if (! $userId) {
|
||||
return response()->json([
|
||||
@@ -121,16 +141,16 @@ class AuthController extends Controller
|
||||
], 401);
|
||||
}
|
||||
|
||||
$this->invalidateRefreshToken($refreshToken, $userId);
|
||||
$this->jwtService->invalidateRefreshToken($refreshToken, $userId);
|
||||
|
||||
$accessToken = $this->generateAccessToken($user);
|
||||
$newRefreshToken = $this->generateRefreshToken($user);
|
||||
$accessToken = $this->jwtService->generateAccessToken($user);
|
||||
$newRefreshToken = $this->jwtService->generateRefreshToken($user);
|
||||
|
||||
return response()->json([
|
||||
'access_token' => $accessToken,
|
||||
'refresh_token' => $newRefreshToken,
|
||||
'token_type' => 'bearer',
|
||||
'expires_in' => 3600,
|
||||
'expires_in' => $this->jwtService->getAccessTokenTTL(),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -150,99 +170,11 @@ class AuthController extends Controller
|
||||
$refreshToken = $request->input('refresh_token');
|
||||
|
||||
if ($refreshToken) {
|
||||
$this->invalidateRefreshToken($refreshToken, $user->id);
|
||||
$this->jwtService->invalidateRefreshToken($refreshToken, $user?->id);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Logged out successfully',
|
||||
]);
|
||||
}
|
||||
|
||||
protected function generateAccessToken(User $user): string
|
||||
{
|
||||
$payload = [
|
||||
'iss' => config('app.url', 'headroom'),
|
||||
'sub' => $user->id,
|
||||
'iat' => time(),
|
||||
'exp' => time() + 3600,
|
||||
'role' => $user->role,
|
||||
'permissions' => $this->getPermissions($user->role),
|
||||
'jti' => uniqid('token_', true),
|
||||
];
|
||||
|
||||
return $this->encodeJWT($payload);
|
||||
}
|
||||
|
||||
protected function generateRefreshToken(User $user): string
|
||||
{
|
||||
$token = bin2hex(random_bytes(32));
|
||||
// Store with token as the key part for easy lookup
|
||||
$key = "refresh_token:{$token}";
|
||||
Redis::setex($key, 604800, $user->id);
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
protected function getUserIdFromRefreshToken(string $token): ?string
|
||||
{
|
||||
return Redis::get("refresh_token:{$token}") ?: null;
|
||||
}
|
||||
|
||||
protected function invalidateRefreshToken(string $token, string $userId): void
|
||||
{
|
||||
Redis::del("refresh_token:{$token}");
|
||||
}
|
||||
|
||||
protected function getPermissions(string $role): array
|
||||
{
|
||||
return match ($role) {
|
||||
'superuser' => [
|
||||
'manage_users',
|
||||
'manage_team_members',
|
||||
'manage_projects',
|
||||
'manage_allocations',
|
||||
'manage_actuals',
|
||||
'view_reports',
|
||||
'configure_system',
|
||||
'view_audit_logs',
|
||||
],
|
||||
'manager' => [
|
||||
'manage_projects',
|
||||
'manage_allocations',
|
||||
'manage_actuals',
|
||||
'view_reports',
|
||||
'manage_team_members',
|
||||
],
|
||||
'developer' => [
|
||||
'manage_actuals',
|
||||
'view_own_allocations',
|
||||
'view_own_actuals',
|
||||
'log_hours',
|
||||
],
|
||||
'top_brass' => [
|
||||
'view_reports',
|
||||
'view_allocations',
|
||||
'view_actuals',
|
||||
'view_capacity',
|
||||
],
|
||||
default => [],
|
||||
};
|
||||
}
|
||||
|
||||
protected function encodeJWT(array $payload): string
|
||||
{
|
||||
$header = json_encode(['typ' => 'JWT', 'alg' => 'HS256']);
|
||||
$header = base64_encode($header);
|
||||
$header = str_replace(['+', '/', '='], ['-', '_', ''], $header);
|
||||
|
||||
$payload = json_encode($payload);
|
||||
$payload = base64_encode($payload);
|
||||
$payload = str_replace(['+', '/', '='], ['-', '_', ''], $payload);
|
||||
|
||||
$signature = hash_hmac('sha256', $header . '.' . $payload, config('app.key'), true);
|
||||
$signature = base64_encode($signature);
|
||||
$signature = str_replace(['+', '/', '='], ['-', '_', ''], $signature);
|
||||
|
||||
return $header . '.' . $payload . '.' . $signature;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user