|
|
|
|
<?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;
|
|
|
|
|
}
|
|
|
|
|
}
|