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

Laravel Sanctum登录后访问受保护路由返回401未认证求助

React SPA 配置 Laravel Sanctum 认证后访问受保护路由返回401未认证

环境信息

  • SPA地址:localhost:3000
  • 后端地址:https://local-erp.XXX.com/

配置文件

sanctum.php

'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
    '%s%s',
    'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1,https://local-erp.XXX.com',
    Sanctum::currentApplicationUrlWithPort()
))),

kernel.php

protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
        \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
        \Illuminate\Routing\Middleware\ThrottleRequests::class . ':api',
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
];

.env

SESSION_DOMAIN:.localhost

曾尝试设置为*.localhost和localhost

LoginController 代码

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use App\Service\Ldap;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;

class LoginController extends Controller
{
    use AuthenticatesUsers;

    protected $redirectTo = RouteServiceProvider::HOME;

    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

    public function username()
    {
        return 'username';
    }

    protected function credentials(Request $request)
    {
        return [
            'sAMAccountName' => $request->username,
            'password' => $request->password
        ];
    }
}

前端请求代码

登录请求

axios.get("https://local-erp.XXX.com/sanctum/csrf-cookie").then(response => {
    axios.post("https://local-erp.XXX.com/login",  {username: "xxx", password: "xxxx"})
})

以上请求均返回204状态码。

测试受保护路由请求

const querytest = () => {
    axios.get('https://local-erp.XXX.com/api/users/5/holiday-balance')
}

返回结果:{"message":"Unauthenticated."}

解决方案建议

1. 开启Axios跨域Cookie传递

Sanctum依赖Cookie传递会话状态,前端必须开启withCredentials:

// 在axios初始化时添加全局配置
axios.defaults.withCredentials = true;
// 建议设置baseURL简化请求
axios.defaults.baseURL = 'https://local-erp.XXX.com';

2. 修正后端CORS配置

修改config/cors.php,确保允许跨域凭证并包含前端域名:

return [
    'paths' => ['api/*', 'sanctum/csrf-cookie', 'login', 'logout'],
    'allowed_methods' => ['*'],
    'allowed_origins' => ['http://localhost:3000'],
    'allowed_origins_patterns' => [],
    'allowed_headers' => ['*'],
    'exposed_headers' => [],
    'max_age' => 0,
    'supports_credentials' => true,
];

3. 修正SESSION_DOMAIN配置

由于后端域名local-erp.XXX.com与前端localhost:3000是不同域,需将.env中的SESSION_DOMAIN设为后端域名:

SESSION_DOMAIN=local-erp.XXX.com

4. 清理Sanctum Stateful Domains

移除stateful配置中的后端域名,只保留前端相关地址,修改.env:

SANCTUM_STATEFUL_DOMAINS=localhost,localhost:3000

或直接修改sanctum.php:

'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost,localhost:3000,127.0.0.1')),

5. 验证路由中间件

确认受保护路由在routes/api.php中正确使用auth:sanctum中间件:

Route::get('/users/{user}/holiday-balance', [UserController::class, 'getHolidayBalance'])
    ->middleware('auth:sanctum');

6. 清除缓存

修改配置后执行以下命令清除配置缓存:

php artisan config:clear
php artisan cache:clear

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 01:12:28