feat(auth): implement AdminApp login functionality with controller, request, routes, and tests
This commit is contained in:
@@ -5,6 +5,7 @@ namespace App\Domains\Auth\Services;
|
||||
use App\Domains\Auth\Exceptions\AccountLockedException;
|
||||
use App\Domains\Auth\Models\LoginAttempt;
|
||||
use App\Domains\Auth\Models\User;
|
||||
use App\Domains\Authorization\Enums\RoleCode;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
@@ -22,6 +23,48 @@ class PasswordLoginService
|
||||
string $tenantCode,
|
||||
?string $ipAddress,
|
||||
?string $userAgent,
|
||||
): User {
|
||||
return $this->authenticateUser(
|
||||
$email,
|
||||
$password,
|
||||
$tenantCode,
|
||||
$ipAddress,
|
||||
$userAgent,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate a tenant-bound AdminApp user without requiring the caller
|
||||
* to know their tenant code beforehand.
|
||||
*
|
||||
* @throws AccountLockedException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function authenticateAdminApp(
|
||||
string $email,
|
||||
string $password,
|
||||
?string $ipAddress,
|
||||
?string $userAgent,
|
||||
): User {
|
||||
return $this->authenticateUser(
|
||||
$email,
|
||||
$password,
|
||||
null,
|
||||
$ipAddress,
|
||||
$userAgent,
|
||||
RoleCode::AdminApp,
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
private function authenticateUser(
|
||||
string $email,
|
||||
string $password,
|
||||
?string $tenantCode,
|
||||
?string $ipAddress,
|
||||
?string $userAgent,
|
||||
RoleCode $requiredRole = RoleCode::User,
|
||||
bool $requiresTenant = false,
|
||||
): User {
|
||||
$normalizedEmail = mb_strtolower(trim($email));
|
||||
$now = CarbonImmutable::now();
|
||||
@@ -34,17 +77,25 @@ class PasswordLoginService
|
||||
$ipAddress,
|
||||
$userAgent,
|
||||
$now,
|
||||
$requiredRole,
|
||||
$requiresTenant,
|
||||
): array {
|
||||
$user = User::query()
|
||||
->where('email', $normalizedEmail)
|
||||
->where('rol_codigo', $requiredRole->value)
|
||||
->when(
|
||||
$requiresTenant,
|
||||
fn ($query) => $query->whereNotNull('tenant_codigo'),
|
||||
)
|
||||
->lockForUpdate()
|
||||
->first();
|
||||
$attemptTenantCode = $tenantCode ?? $user?->tenant_codigo;
|
||||
|
||||
if ($user?->locked_until?->isFuture()) {
|
||||
$this->recordAttempt(
|
||||
$user,
|
||||
$normalizedEmail,
|
||||
$tenantCode,
|
||||
$attemptTenantCode,
|
||||
LoginAttempt::OUTCOME_ACCOUNT_LOCKED,
|
||||
$ipAddress,
|
||||
$userAgent,
|
||||
@@ -76,7 +127,7 @@ class PasswordLoginService
|
||||
$this->recordAttempt(
|
||||
$user,
|
||||
$normalizedEmail,
|
||||
$tenantCode,
|
||||
$attemptTenantCode,
|
||||
$outcome,
|
||||
$ipAddress,
|
||||
$userAgent,
|
||||
@@ -100,7 +151,7 @@ class PasswordLoginService
|
||||
$this->recordAttempt(
|
||||
$user,
|
||||
$normalizedEmail,
|
||||
$tenantCode,
|
||||
$attemptTenantCode,
|
||||
LoginAttempt::OUTCOME_SUCCESS,
|
||||
$ipAddress,
|
||||
$userAgent,
|
||||
@@ -150,7 +201,7 @@ class PasswordLoginService
|
||||
private function recordAttempt(
|
||||
?User $user,
|
||||
string $normalizedEmail,
|
||||
string $tenantCode,
|
||||
?string $tenantCode,
|
||||
string $outcome,
|
||||
?string $ipAddress,
|
||||
?string $userAgent,
|
||||
|
||||
Reference in New Issue
Block a user