feat(auth): implement permission-based access for scanner functionality and update related tests
This commit is contained in:
@@ -53,6 +53,16 @@ class User extends Authenticatable
|
||||
return $this->belongsTo(Role::class, 'rol_codigo', 'codigo');
|
||||
}
|
||||
|
||||
public function hasPermission(string $permissionCode): bool
|
||||
{
|
||||
return $this->role()
|
||||
->whereHas(
|
||||
'permissions',
|
||||
fn ($query) => $query->where('permisos.codigo', $permissionCode)
|
||||
)
|
||||
->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Tenant, $this>
|
||||
*/
|
||||
|
||||
@@ -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\PermissionCode;
|
||||
use App\Domains\Authorization\Enums\RoleCode;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@@ -63,7 +64,7 @@ class PasswordLoginService
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate a tenant-bound scanner without requiring its tenant code.
|
||||
* Authenticate a tenant-bound user authorized to scan tickets.
|
||||
*
|
||||
* @throws AccountLockedException
|
||||
* @throws ValidationException
|
||||
@@ -80,8 +81,9 @@ class PasswordLoginService
|
||||
null,
|
||||
$ipAddress,
|
||||
$userAgent,
|
||||
RoleCode::Scanner,
|
||||
null,
|
||||
true,
|
||||
PermissionCode::ScanTickets->value,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -91,8 +93,9 @@ class PasswordLoginService
|
||||
?string $tenantCode,
|
||||
?string $ipAddress,
|
||||
?string $userAgent,
|
||||
RoleCode $requiredRole = RoleCode::User,
|
||||
?RoleCode $requiredRole = RoleCode::User,
|
||||
bool $requiresTenant = false,
|
||||
?string $requiredPermission = null,
|
||||
): User {
|
||||
$normalizedEmail = mb_strtolower(trim($email));
|
||||
$now = CarbonImmutable::now();
|
||||
@@ -107,10 +110,21 @@ class PasswordLoginService
|
||||
$now,
|
||||
$requiredRole,
|
||||
$requiresTenant,
|
||||
$requiredPermission,
|
||||
): array {
|
||||
$user = User::query()
|
||||
->where('email', $normalizedEmail)
|
||||
->where('rol_codigo', $requiredRole->value)
|
||||
->when(
|
||||
$requiredRole !== null,
|
||||
fn ($query) => $query->where('rol_codigo', $requiredRole->value),
|
||||
)
|
||||
->when(
|
||||
$requiredPermission !== null,
|
||||
fn ($query) => $query->whereHas(
|
||||
'role.permissions',
|
||||
fn ($query) => $query->where('permisos.codigo', $requiredPermission)
|
||||
),
|
||||
)
|
||||
->when(
|
||||
$requiresTenant,
|
||||
fn ($query) => $query->whereNotNull('tenant_codigo'),
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Domains\Auth\Services;
|
||||
|
||||
use App\Domains\Auth\Models\User;
|
||||
use App\Domains\Authorization\Enums\RoleCode;
|
||||
|
||||
class ScannerContextService
|
||||
{
|
||||
@@ -13,7 +12,7 @@ class ScannerContextService
|
||||
->with([
|
||||
'menues' => fn ($query) => $query->whereHas(
|
||||
'roles',
|
||||
fn ($query) => $query->where('codigo', RoleCode::Scanner->value)
|
||||
fn ($query) => $query->where('codigo', $user->rol_codigo)
|
||||
),
|
||||
])
|
||||
->firstOrFail();
|
||||
|
||||
8
app/Domains/Authorization/Enums/PermissionCode.php
Normal file
8
app/Domains/Authorization/Enums/PermissionCode.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Authorization\Enums;
|
||||
|
||||
enum PermissionCode: string
|
||||
{
|
||||
case ScanTickets = 'tickets.escanear';
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Domains\Authorization\Enums\RoleCode;
|
||||
use App\Domains\Authorization\Enums\PermissionCode;
|
||||
use Closure;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -11,7 +11,7 @@ use Symfony\Component\HttpFoundation\Response;
|
||||
class EnsureScannerTenant
|
||||
{
|
||||
/**
|
||||
* Ensure the authenticated user is a scanner bound to a tenant.
|
||||
* Ensure the authenticated user can scan tickets for a tenant.
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
@@ -19,8 +19,8 @@ class EnsureScannerTenant
|
||||
|
||||
if (
|
||||
! $user
|
||||
|| $user->rol_codigo !== RoleCode::Scanner->value
|
||||
|| ! $user->tenant_codigo
|
||||
|| ! $user->hasPermission(PermissionCode::ScanTickets->value)
|
||||
) {
|
||||
throw new AuthorizationException;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user