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

Laravel自动添加Authorization令牌中间件问题求助

问题分析

你遇到的核心问题是中间件执行顺序错误:auth中间件(默认是web守卫,会触发登录页重定向)在你的AutoAssignGuestToken中间件之前执行,导致请求还没来得及附加Authorization头,就被拦截重定向了。另外现有实现还存在几个逻辑漏洞:

  • API路由误用web守卫,不符合无状态API的特性,会触发不必要的重定向
  • 访客用户创建逻辑未复用已有有效账号,会导致数据库堆积大量重复Guest用户
  • 手动拆分验证token的方式易出错,Laravel Sanctum自带完善的token验证机制
解决方案

1. 调整中间件优先级

在app/Http/Kernel.php中,将AutoAssignGuestToken注册到api中间件组,并且放在auth:sanctum之前,确保token先被附加再执行认证:

protected $middlewareGroups = [
    'api' => [
        \App\Http\Middleware\AutoAssignGuestToken::class,
        'throttle:api',
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
        \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
        'auth:sanctum', // 必须放在自动分配中间件之后
    ],
];

2. 优化中间件实现代码

以下是修复后的完整代码,解决了重定向、重复创建用户、token验证等问题:

<?php

namespace App\Http\Middleware;

use App\Models\User;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Laravel\Sanctum\PersonalAccessToken;
use Symfony\Component\HttpFoundation\Response;

class AutoAssignGuestToken
{
    public function handle(Request $request, Closure $next): Response
    {
        $bearerToken = $request->bearerToken();
        $validToken = false;

        // 验证请求头中的token是否有效
        if ($bearerToken) {
            $token = PersonalAccessToken::findToken($bearerToken);
            $validToken = $token && !$token->expired();
        }

        // 请求头token无效时,尝试从cookie读取访客token并验证
        if (!$validToken) {
            $guestToken = $request->cookie('guest_token');
            if ($guestToken) {
                $token = PersonalAccessToken::findToken($guestToken);
                $validToken = $token && !$token->expired();
                if ($validToken) {
                    $request->headers->set('Authorization', 'Bearer ' . $guestToken);
                    Auth::guard('sanctum')->loginUsingId($token->tokenable_id);
                }
            }
        }

        // 无有效token时,创建新访客账号和token
        if (!$validToken) {
            $bearerToken = $this->createGuestToken($request);
        }

        $response = $next($request);

        // 新创建token时,写入cookie保存(httpOnly提升安全性)
        if (isset($bearerToken)) {
            $response->withCookie(cookie('guest_token', $bearerToken, 60 * 24 * 7, null, null, false, true));
            // 如需在响应返回token,可取消下方注释
            // $content = json_decode($response->getContent(), true);
            // $content['data']['token'] = $bearerToken;
            // $response->setContent(json_encode($content));
        }

        return $response;
    }

    protected function createGuestToken(Request $request): string
    {
        // 创建带标记的访客用户(建议给User模型加is_guest字段,方便后续区分)
        $guest = User::create([
            'name' => 'Guest_' . uniqid(),
            'email' => 'guest_' . uniqid() . '@example.com', // 若User模型必填email,生成临时邮箱
            'is_guest' => true,
        ]);

        // 使用Sanctum创建API token
        $plainTextToken = $guest->createToken('Guest Token')->plainTextToken;

        // 给请求附加Authorization头并登录访客用户
        $request->headers->set('Authorization', 'Bearer ' . $plainTextToken);
        Auth::guard('sanctum')->login($guest);

        return $plainTextToken;
    }
}

3. 关键改动说明

  • 守卫切换:改用auth:sanctum守卫,避免API请求被重定向到登录页,符合无状态API特性
  • token验证:使用Sanctum自带的PersonalAccessToken::findToken()方法验证,比手动拆分更可靠
  • 访客复用:优先验证cookie中的访客token,有效则直接复用,避免数据库冗余
  • 安全优化:设置cookie为httpOnly,防止前端XSS窃取token
  • 顺序保障:确保自动分配中间件在认证中间件之前执行,保证认证逻辑触发前请求已携带有效token

4. 路由配置示例

确保API路由使用api中间件组:

Route::middleware(['api'])->group(function () {
    // 需要认证的API路由示例
    Route::get('/protected-data', function () {
        return response()->json(['user' => auth()->user(), 'message' => '访问受保护数据成功']);
    });
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 12:44:58