419 页面使用 laravel sanctum 过期

Posted

技术标签:

【中文标题】419 页面使用 laravel sanctum 过期【英文标题】:419 Page expired using laravel sanctum 【发布时间】:2021-04-22 08:37:42 【问题描述】:

我仍在构建使用 SPA 的身份验证方法,我已经安装了 laravel sanctum 并按照正确的步骤在欢迎刀片上创建了一个演示表单,只是为了测试一下,我正在使用正确接收 xsrf-cookie sanctum/csrf-cookie,但是登录返回 419 页面已过期。我试过清除缓存、路由、配置

服务于 localhost:8000

.env

SANCTUM_STATEFUL_DOMAINS=localhost:8000
SESSION_DOMAIN=localhost

cors

    'paths' => ['api/*','login','sanctum/csrf-cookie'],

    'allowed_methods' => ['*'],

    'allowed_origins' => ['*'],

    'allowed_origins_patterns' => [],

    'allowed_headers' => ['*'],

    'exposed_headers' => [],

    'max_age' => 0,

    'supports_credentials' => true,

];

网络路由

Route::post('login', function()
    echo"a";
);
// Route::post('register', [UserController::class,'register']);

Route::get('/',function()
    return view('welcome');
);

表格

    <form method="post" action="/login">
        <button type="submit">Submit</button>
    </form>

我手动访问 localhost:8000/sanctum/csrf-cookie,我可以看到正在设置 xsrf 和会话的 cookie,在提交时我仍然得到 419 页面过期。 (添加@csrf 使其工作,但是,这只是为了测试,我打算使用 SPA)

【问题讨论】:

我刚刚从头开始安装了 laravel 和 sanctum,运行了 php artisan serve,将 .env 中的域和有状态域更改为 localhost,添加了登录到 cors,它仍然无法正常工作。 【参考方案1】:

这对我来说是这样的:

在kernel.php中

  'api' => [
            \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            'throttle:5000,1',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
            \Illuminate\Session\Middleware\StartSession::class
        ],

在 config/sanctum.php 中

  <?php

 return [

/*
|--------------------------------------------------------------------------
| Stateful Domains
|--------------------------------------------------------------------------
|
| Requests from the following domains / hosts will receive stateful API
| authentication cookies. Typically, these should include your local
| and production domains which access your API via a frontend SPA.
|
*/

'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
    '%s%s',
    'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
    env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
))),

/*
|--------------------------------------------------------------------------
| Expiration Minutes
|--------------------------------------------------------------------------
|
| This value controls the number of minutes until an issued token will be
| considered expired. If this value is null, personal access tokens do
| not expire. This won't tweak the lifetime of first-party sessions.
|
*/

'expiration' => null,

/*
|--------------------------------------------------------------------------
| Sanctum Middleware
|--------------------------------------------------------------------------
|
| When authenticating your first-party SPA with Sanctum you may need to
| customize some of the middleware Sanctum uses while processing the
| request. You may change the middleware listed below as required.
|
*/

'middleware' => [
    'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class,
    'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class,
],

];

在 .env 中(我对主要 API 和 SPA 网站都使用子域)

 SESSION_DRIVER=cookie
 SESSION_LIFETIME=86400
 SESSION_DOMAIN=".myapidomain.com"
 SANCTUM_STATEFUL_DOMAINS=".myapidomain.com"

在 cors.php 中

   'paths' => ['api/*','sanctum/csrf-cookie'],
   'supports_credentials' => true,

在用户模型中,例如:App\User

   use Laravel\Sanctum\HasApiTokens;

我没有在前端使用 vuejs,所以我使用了 Laravel HTTP Facade,所以我创建了一个类来管理认证请求和非认证请求的 SPA 请求

    <?php

    namespace App\Http\Controllers\Api\Settings;

    use GuzzleHttp\Client;
    use Illuminate\Support\Facades\Http;
    use Illuminate\Support\Facades\Session;

   class Master
   


public $domainApiLink = "https://subdomain.mydomain/api/";
public $domainWebLink = "https://sbdomain.mydomain.com/";

private $cookies;

public function __construct()
    $this->generate_cookies();


public function generate_cookies()
    if(empty(Session::get('cookies'))) 
       
            $cookies = Http::acceptJson()->asJson()->get($this->domainWebLink . 'sanctum/csrf-cookie')->throw()->cookies();
            Session::put('cookies', $cookies);
    


public function getRequest($get_link_part, $type = '')

    $activeLocale = app()->getLocale();
    if(Session::has('auth_token') ) 
        $response = Http::acceptJson()->asJson()
            ->withToken( Session::get('auth_token'))
            ->withOptions([
                //'debug' => true
            ])
            ->get($this->domainApiLink . $activeLocale . $get_link_part)
            ->throw();
    else
          $response = Http::acceptJson()->asJson()
            ->withToken($this->website_token)
            ->withOptions([
                //'debug' => true,
                'cookies' => Session::get('cookies'),
            ])
            ->get($this->domainApiLink . $activeLocale . $get_link_part)
            ->throw();
    
    switch ($type) 
        case 'json':
            $response = $response->json();
            break;
        case 'assoc':
            if (is_array($response->json())) 
                return $response->json();
             else 
                $response = json_decode($response->json(), true);
                if (empty($response)) 
                    return ['error' => 'Invalid Json response'];
                
            
            break;
        case 'object':
            $response = $response->object();
            break;
        default:
            $response = $response->body();
            break;
    
    return $response;


public function postRequest($inputs, $get_link_part, $type = '')

    $activeLocale = app()->getLocale();
    if(Session::has('auth_token') ) 
        $response = Http::acceptJson()->asJson()
            ->withToken(Session::get('auth_token'))
            //->withOptions(['debug' => true])
            ->post($this->domainApiLink . $activeLocale . $get_link_part, $inputs)
            ->throw();
    
    else
        $response = Http::acceptJson()->asJson()
            ->withToken($this->website_token)
            ->withOptions([
                //'debug' => true,
            ])
            ->post($this->domainApiLink. $activeLocale . $get_link_part, $inputs)
            ->throw();
    
    switch ($type) 
        case 'json':
            $result = $response->json();
            break;
        case 'assoc':
            if (is_array($response->json())) 
                $result =  $response->json();
             else 
                $result = json_decode($response->json(), true);
                if (empty($result)) 
                    $result = ['error' => 'Invalid Json response'];
                
            
            break;
        case 'object':
            $result = $response->object();
            break;
        default:
            $result = $response->body();
            break;
    
    return $result;

    /**
    * @return mixed
    */
    public function getCookies()
    
       return $this->cookies;
    

    /**
    * @param mixed $cookie
    */
    public function setCookies($cookie): void
    
        $this->cookies = $cookie;
    


我希望这对您有所帮助,如果需要,我很乐意解释更多

【讨论】:

以上是关于419 页面使用 laravel sanctum 过期的主要内容,如果未能解决你的问题,请参考以下文章

Laravel Sanctum 和使用 Pusher.js 进行广播(401、419 错误)

Vue + Laravel sanctum CSRF 令牌不匹配 419 错误

Laravel Sanctum 突然令牌不匹配,仅在清除浏览器 cookie 后有效

当页面更新时,数据被删除 - vue 和 laravel sanctum

laravel 5.8.7 页面过期(419)

Laravel 页面已过期 419