update controllers logic
This commit is contained in:
@@ -0,0 +1,257 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Auth\LoginSessionRequest;
|
||||
use App\Http\Requests\Auth\SetRoleSessionRequest;
|
||||
use App\Models\User;
|
||||
use App\Services\ApplicationUrlService;
|
||||
use App\Services\Auth\ApiLoginSecurityService;
|
||||
use App\Services\Auth\AuthSessionService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
/**
|
||||
* Session (cookie) endpoints for SPA — JSON alongside JWT on /api/login.
|
||||
*
|
||||
* Routes: GET login, POST user/login, GET logout, GET select-role, POST set-role (registered on web middleware).
|
||||
*/
|
||||
class AuthSessionController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private ApiLoginSecurityService $security,
|
||||
private AuthSessionService $sessionAuth,
|
||||
private ApplicationUrlService $urls,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* CI `loginMask` — login page bootstrap / redirect when already authenticated.
|
||||
*/
|
||||
public function loginMask(Request $request): JsonResponse
|
||||
{
|
||||
$redirectTo = $this->sessionAuth->sanitizeRedirectTarget(
|
||||
(string) ($request->query('redirect_to') ?? ''),
|
||||
);
|
||||
|
||||
if (! Auth::guard('web')->check()) {
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'authenticated' => false,
|
||||
'redirect_to' => $redirectTo,
|
||||
]);
|
||||
}
|
||||
|
||||
/** @var list<string>|null $roles */
|
||||
$roles = session('roles');
|
||||
$roles = is_array($roles) ? array_values(array_filter(array_map('strval', $roles))) : [];
|
||||
$currentRole = session('role');
|
||||
|
||||
if ($roles !== [] && count($roles) > 1 && ! $currentRole) {
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'authenticated' => true,
|
||||
'next_url' => $this->urls->webSelectRoleUrl(false),
|
||||
'roles' => $roles,
|
||||
'pending_redirect' => session('post_login_redirect'),
|
||||
]);
|
||||
}
|
||||
|
||||
if ($redirectTo !== null) {
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'authenticated' => true,
|
||||
'next_url' => $redirectTo,
|
||||
]);
|
||||
}
|
||||
|
||||
$pick = $currentRole !== null && $currentRole !== ''
|
||||
? [(string) $currentRole]
|
||||
: $roles;
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'authenticated' => true,
|
||||
'next_url' => $this->sessionAuth->dashboardRouteForRoles($pick),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* CI `login` — POST /user/login.
|
||||
*/
|
||||
public function login(LoginSessionRequest $request): JsonResponse
|
||||
{
|
||||
$email = (string) $request->validated('email');
|
||||
$password = (string) $request->validated('password');
|
||||
$redirectRaw = $request->validated('redirect_to');
|
||||
$sanitizedRedirect = $redirectRaw !== null
|
||||
? $this->sessionAuth->sanitizeRedirectTarget((string) $redirectRaw)
|
||||
: null;
|
||||
|
||||
$ip = (string) $request->ip();
|
||||
|
||||
if ($this->security->isIpBlocked($ip)) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Too many failed attempts from your IP. Please try again later.',
|
||||
], 429);
|
||||
}
|
||||
|
||||
$user = User::query()->where('email', $email)->first();
|
||||
|
||||
if (! $user) {
|
||||
$this->security->logIpAttempt($ip);
|
||||
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'The email and password combination you entered is invalid. Please try again.',
|
||||
], 401);
|
||||
}
|
||||
|
||||
if ($user->is_suspended) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Account suspended. Please check your email to reset your password.',
|
||||
], 403);
|
||||
}
|
||||
|
||||
if (! ci_password_verify($password, (string) $user->password)) {
|
||||
$this->security->handleFailedLogin($user, $email, $ip);
|
||||
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'The email and password combination you entered is invalid. Please try again.',
|
||||
], 401);
|
||||
}
|
||||
|
||||
$fresh = $user->fresh();
|
||||
if (! $fresh) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'The email and password combination you entered is invalid. Please try again.',
|
||||
], 401);
|
||||
}
|
||||
|
||||
$this->security->resetFailedAttempts($fresh);
|
||||
$this->security->logSuccessfulLogin($fresh, $request);
|
||||
|
||||
$dest = $this->sessionAuth->resolvePostLoginDestination($fresh, $sanitizedRedirect);
|
||||
|
||||
if (($dest['kind'] ?? '') === 'no_roles') {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => (string) ($dest['reason'] ?? 'Role not assigned. Please contact support.'),
|
||||
], 403);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'requires_role_selection' => ($dest['kind'] ?? '') === 'select_role',
|
||||
'roles' => $dest['roles'] ?? null,
|
||||
'next_url' => $dest['redirect_url'] ?? $this->urls->docsHomeUrl(false),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* CI `logout` — GET /logout.
|
||||
*/
|
||||
public function logout(Request $request): JsonResponse
|
||||
{
|
||||
$userId = Auth::guard('web')->id();
|
||||
$email = Auth::guard('web')->user()?->email ?? session('user_email');
|
||||
|
||||
$this->sessionAuth->logLogout($userId ? (int) $userId : null, $email ? (string) $email : null);
|
||||
|
||||
Auth::guard('web')->logout();
|
||||
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'next_url' => $this->urls->docsHomeUrl(false),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* CI `selectRole` — GET /select-role.
|
||||
*/
|
||||
public function selectRole(Request $request): JsonResponse
|
||||
{
|
||||
if (! Auth::guard('web')->check()) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'No roles available.',
|
||||
], 401);
|
||||
}
|
||||
|
||||
/** @var list<string>|null $roles */
|
||||
$roles = session('roles');
|
||||
$roles = is_array($roles) ? array_values(array_filter(array_map('strval', $roles))) : [];
|
||||
|
||||
if ($roles === []) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'No roles available.',
|
||||
], 422);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'roles' => $roles,
|
||||
'pending_redirect' => session('post_login_redirect'),
|
||||
'redirect_to_query' => $this->sessionAuth->sanitizeRedirectTarget(
|
||||
(string) ($request->query('redirect_to') ?? ''),
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* CI `setRole` — POST /set-role.
|
||||
*/
|
||||
public function setRole(SetRoleSessionRequest $request): JsonResponse
|
||||
{
|
||||
if (! Auth::guard('web')->check()) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Unauthorized.',
|
||||
], 401);
|
||||
}
|
||||
|
||||
$selectedRole = (string) $request->validated('selected_role');
|
||||
|
||||
/** @var list<string>|null $available */
|
||||
$available = session('roles');
|
||||
$available = is_array($available) ? array_values(array_filter(array_map('strval', $available))) : [];
|
||||
|
||||
if ($available === [] || ! in_array($selectedRole, $available, true)) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Invalid role selected.',
|
||||
], 422);
|
||||
}
|
||||
|
||||
$redirectRaw = $request->validated('redirect_to');
|
||||
$redirectTo = $redirectRaw !== null
|
||||
? $this->sessionAuth->sanitizeRedirectTarget((string) $redirectRaw)
|
||||
: null;
|
||||
|
||||
if ($redirectTo === null) {
|
||||
$redirectTo = $this->sessionAuth->sanitizeRedirectTarget(
|
||||
(string) (session('post_login_redirect') ?? ''),
|
||||
);
|
||||
}
|
||||
|
||||
session(['role' => $selectedRole]);
|
||||
session()->forget('post_login_redirect');
|
||||
|
||||
$next = $redirectTo ?? $this->sessionAuth->dashboardRouteForRoles([$selectedRole]);
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'role' => $selectedRole,
|
||||
'next_url' => $next,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user