You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 8 Sanctum个人访问令牌:Web路由鉴权重定向问题

Laravel Sanctum 令牌重定向Web路由401问题解决方案

问题核心原因

  1. auth:sanctum中间件在Web路由场景下,默认优先检查会话(Session)认证状态,而非请求头中的Bearer令牌。
  2. 重定向属于浏览器发起的全新请求,你在前端控制器中设置的Authorization请求头不会被自动携带到重定向后的请求中。
  3. XSRF-TOKEN Cookie主要影响跨域POST/PUT/DELETE请求的合法性,重定向的GET请求若为同域,一般不是401的直接原因,但跨域场景需额外配置。

可行解决方案

方案一:将令牌存入Cookie,通过中间件自动注入请求头

这种方案让Web请求自动携带令牌,适配auth:sanctum的令牌认证逻辑:

  1. 前端处理令牌存储:拿到后端返回的loginToken后,将其存入HttpOnly Cookie(避免XSS风险)

    // 假设从API响应中获取到loginToken
    const loginToken = response.data.loginToken;
    // 设置Cookie,确保路径覆盖所有受保护路由
    document.cookie = `sanctum_token=${loginToken}; path=/; HttpOnly; SameSite=Lax`;
    // 执行重定向
    window.location.href = '/admin/dashboard';
    
  2. 自定义中间件注入Authorization头
    创建app/Http/Middleware/InjectSanctumToken.php:

    <?php
    
    namespace App\Http\Middleware;
    
    use Closure;
    use Illuminate\Http\Request;
    
    class InjectSanctumToken
    {
        public function handle(Request $request, Closure $next)
        {
            // 从Cookie读取令牌,若存在则注入请求头
            if ($token = $request->cookie('sanctum_token')) {
                $request->headers->set('Authorization', "Bearer {$token}");
            }
    
            return $next($request);
        }
    }
    
  3. 注册中间件到Web组
    在app/Http/Kernel.php的web中间件组中,将自定义中间件放在auth:sanctum之前:

    protected $middlewareGroups = [
        'web' => [
            // ...其他默认中间件
            \App\Http\Middleware\InjectSanctumToken::class,
            \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            'auth:sanctum',
            // ...
        ],
    ];
    

方案二:将令牌转换为会话登录状态

这种方案更贴合Laravel传统Web认证逻辑,把API获取的令牌转换为Session登录:

  1. 后端新增令牌转换路由
    在routes/web.php中添加:

    use Illuminate\Http\Request;
    use Laravel\Sanctum\PersonalAccessToken;
    
    Route::post('/sanctum/login-with-token', function(Request $request) {
        $token = $request->input('loginToken');
        // 验证令牌有效性
        $personalToken = PersonalAccessToken::findToken($token);
        
        if (!$personalToken || $personalToken->expired()) {
            return back()->withErrors(['token' => '无效或过期的令牌']);
        }
    
        // 将令牌所属用户登录到会话
        auth()->login($personalToken->tokenable);
        // 重定向到受保护路由
        return redirect('/admin/dashboard');
    });
    
  2. 前端提交令牌到转换路由
    拿到loginToken后,通过POST请求提交到上述路由,而非直接重定向:

    const loginToken = response.data.loginToken;
    // 创建表单提交(避免AJAX跨域问题,若同域也可用fetch)
    const form = document.createElement('form');
    form.method = 'POST';
    form.action = '/sanctum/login-with-token';
    // 添加CSRF令牌(同域下必须)
    const csrfInput = document.createElement('input');
    csrfInput.type = 'hidden';
    csrfInput.name = '_token';
    csrfInput.value = document.querySelector('meta[name="csrf-token"]').content;
    // 添加令牌参数
    const tokenInput = document.createElement('input');
    tokenInput.type = 'hidden';
    tokenInput.name = 'loginToken';
    tokenInput.value = loginToken;
    
    form.appendChild(csrfInput);
    form.appendChild(tokenInput);
    document.body.appendChild(form);
    form.submit();
    

关键注意事项

  • 若为跨域场景,需在config/sanctum.php中配置stateful数组,包含前端域名。
  • 令牌有效期需合理设置,避免频繁过期导致用户重新登录。
  • 方案二的会话登录会生成Laravel默认的laravel_session Cookie,后续Web请求无需再携带Bearer令牌。

内容的提问来源于stack exchange,提问作者Jorge Mauricio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 19:43:20