You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

76 lines
3.2 KiB

<?php
namespace App\Http\Middleware;
use App\Helpers\ApiResponse;
use App\Helpers\StarterResponseCode;
use App\Models\Admin;
use Closure;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Support\Facades\Crypt;
use Laravel\Sanctum\PersonalAccessToken;
class SanctumJWT
{
use ApiResponse;
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next, $guard)
{
$route = $request->route();
$displayRoute = $guard === 'admin' && $route->named('display.*');
$acceptDisplayCookie = $displayRoute || ($guard === 'admin' && $route->named('admin.me', 'admin.logout'));
$displayCookie = $acceptDisplayCookie ? $request->cookie(Admin::DISPLAY_COOKIE) : null;
$token = $request->bearerToken() ?? ($displayRoute ? null : $request->token);
$fromDisplayCookie = $token === null && is_string($displayCookie) && $displayCookie !== '';
if ($fromDisplayCookie) {
try {
$token = Crypt::decryptString($displayCookie);
} catch (DecryptException $e) {
return $this->fail(StarterResponseCode::JWT_AUTH_FAIL);
}
}
if (!is_string($token) || $token === '') return $this->fail(StarterResponseCode::JWT_AUTH_FAIL);
// 这里入口一个debug模式打开时候可以直接用户id做token测试
if (!$displayRoute && config('app.debug') && preg_match('/^([a-z]+)-(\d+)$/', $token, $parts)) {
if ($parts[1] !== $guard) return $this->fail(StarterResponseCode::JWT_AUTH_FAIL);
$user = auth()->guard($guard)->loginUsingId($parts[2]);
if (!$user || ($user instanceof Admin && $user->isDisplayOnly())) {
return $this->fail(StarterResponseCode::JWT_AUTH_FAIL);
}
return $next($request);
}
$token = PersonalAccessToken::findToken($token);
if (!$token) {
return $this->fail(StarterResponseCode::JWT_AUTH_FAIL);
}
$tokenable = $token->tokenable;
$provider = config("auth.guards.{$guard}.provider");
$model = config("auth.providers.{$provider}.model");
if (!$model || !($tokenable instanceof $model)) {
return $this->fail(StarterResponseCode::JWT_AUTH_FAIL);
}
$isDisplayToken = in_array(Admin::DISPLAY_ABILITY, $token->abilities ?? [], true);
$isDisplayAccount = $tokenable instanceof Admin && $tokenable->isDisplayOnly();
if ($isDisplayToken || $isDisplayAccount || $displayRoute) {
if (!$isDisplayToken || !$isDisplayAccount || !$acceptDisplayCookie) {
return $this->fail(StarterResponseCode::RBAC_FAIL);
}
if (!$fromDisplayCookie || $request->has('token')
|| $token->created_at->lte(now()->subMinutes(Admin::DISPLAY_SESSION_MINUTES))) {
return $this->fail(StarterResponseCode::JWT_AUTH_FAIL);
}
}
auth()->guard($guard)->setUser($tokenable->withAccessToken($token));
$response = $next($request);
return $isDisplayToken ? $response->header('Cache-Control', 'no-store') : $response;
}
}