反应前端中的 CSRF 令牌不匹配

Posted

技术标签:

【中文标题】反应前端中的 CSRF 令牌不匹配【英文标题】:CSRF token mismatch in react front end 【发布时间】:2021-10-04 03:02:58 【问题描述】:

我是 laravel 的新手。我正在为基于 API 的电子商务开发一个注册模块,使用 Laravel 作为 API 后端,react.js 作为前端。 该 api 使用 laravel/sanctum 认证包。完成所有必要的配置后,注册返回 419 错误状态并显示以下消息:

"message": "CSRF token mismatch.",
    "exception": "Symfony\\Component\\HttpKernel\\Exception\\HttpException",
    "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Exceptions\\Handler.php",
    "line": 387,
    "trace": [
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Exceptions\\Handler.php",
            "line": 332,
            "function": "prepareException",
            "class": "Illuminate\\Foundation\\Exceptions\\Handler",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Pipeline.php",
            "line": 51,
            "function": "render",
            "class": "Illuminate\\Foundation\\Exceptions\\Handler",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
            "line": 172,
            "function": "handleException",
            "class": "Illuminate\\Routing\\Pipeline",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Session\\Middleware\\StartSession.php",
            "line": 121,
            "function": "Illuminate\\Pipeline\\closure",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Session\\Middleware\\StartSession.php",
            "line": 64,
            "function": "handleStatefulRequest",
            "class": "Illuminate\\Session\\Middleware\\StartSession",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
            "line": 167,
            "function": "handle",
            "class": "Illuminate\\Session\\Middleware\\StartSession",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse.php",
            "line": 37,
            "function": "Illuminate\\Pipeline\\closure",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
            "line": 167,
            "function": "handle",
            "class": "Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Cookie\\Middleware\\EncryptCookies.php",
            "line": 67,
            "function": "Illuminate\\Pipeline\\closure",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
            "line": 167,
            "function": "handle",
            "class": "Illuminate\\Cookie\\Middleware\\EncryptCookies",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\sanctum\\src\\Http\\Middleware\\EnsureFrontendRequestsAreStateful.php",
            "line": 26,
            "function": "Illuminate\\Pipeline\\closure",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
            "line": 149,
            "function": "Laravel\\Sanctum\\Http\\Middleware\\closure",
            "class": "Laravel\\Sanctum\\Http\\Middleware\\EnsureFrontendRequestsAreStateful",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
            "line": 103,
            "function": "Illuminate\\Pipeline\\closure",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\sanctum\\src\\Http\\Middleware\\EnsureFrontendRequestsAreStateful.php",
            "line": 34,
            "function": "then",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
            "line": 167,
            "function": "handle",
            "class": "Laravel\\Sanctum\\Http\\Middleware\\EnsureFrontendRequestsAreStateful",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
            "line": 103,
            "function": "Illuminate\\Pipeline\\closure",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php",
            "line": 697,
            "function": "then",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php",
            "line": 672,
            "function": "runRouteWithinStack",
            "class": "Illuminate\\Routing\\Router",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php",
            "line": 636,
            "function": "runRoute",
            "class": "Illuminate\\Routing\\Router",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php",
            "line": 625,
            "function": "dispatchToRoute",
            "class": "Illuminate\\Routing\\Router",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php",
            "line": 166,
            "function": "dispatch",
            "class": "Illuminate\\Routing\\Router",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
            "line": 128,
            "function": "Illuminate\\Foundation\\Http\\closure",
            "class": "Illuminate\\Foundation\\Http\\Kernel",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest.php",
            "line": 21,
            "function": "Illuminate\\Pipeline\\closure",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull.php",
            "line": 31,
            "function": "handle",
            "class": "Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
            "line": 167,
            "function": "handle",
            "class": "Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest.php",
            "line": 21,
            "function": "Illuminate\\Pipeline\\closure",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TrimStrings.php",
            "line": 40,
            "function": "handle",
            "class": "Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
            "line": 167,
            "function": "handle",
            "class": "Illuminate\\Foundation\\Http\\Middleware\\TrimStrings",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize.php",
            "line": 27,
            "function": "Illuminate\\Pipeline\\closure",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
            "line": 167,
            "function": "handle",
            "class": "Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance.php",
            "line": 86,
            "function": "Illuminate\\Pipeline\\closure",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
            "line": 167,
            "function": "handle",
            "class": "Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\fruitcake\\laravel-cors\\src\\HandleCors.php",
            "line": 52,
            "function": "Illuminate\\Pipeline\\closure",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
            "line": 167,
            "function": "handle",
            "class": "Fruitcake\\Cors\\HandleCors",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\fideloper\\proxy\\src\\TrustProxies.php",
            "line": 57,
            "function": "Illuminate\\Pipeline\\closure",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
            "line": 167,
            "function": "handle",
            "class": "Fideloper\\Proxy\\TrustProxies",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
            "line": 103,
            "function": "Illuminate\\Pipeline\\closure",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php",
            "line": 141,
            "function": "then",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php",
            "line": 110,
            "function": "sendRequestThroughRouter",
            "class": "Illuminate\\Foundation\\Http\\Kernel",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\public\\index.php",
            "line": 52,
            "function": "handle",
            "class": "Illuminate\\Foundation\\Http\\Kernel",
            "type": "->"
        ,
        
            "file": "C:\\Users\\DELL\\web projects\\development\\api_arms\\server.php",
            "line": 21,
            "function": "require_once"
        
    ]

我需要帮助来解决这个问题。

这是我的源文件:

AuthController.php:

<?php

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use App\Models\User;
use http\Env\Response;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;

class AuthController extends Controller

    public function register(Request $request)
        $validator = Validator::make($request->all(),[
            'name'=>'required',
            'email'=>'required|email|max:191|unique:users,email',
            'password'=>'required|min:6'
        ]);
        if ($validator->fails())
            return response()->json([
                'error'=>$validator->messages()
            ]);
        else
            $user = User::create([
                'name'=>$request->name,
                'email'=>$request->email,
                'password'=>Hash::make($request->password)
            ]);
            $token = $user->createToken($user->email.'_Token')->plainTextToken;

            return response()->json([
                'status'=>200,
                'usename'=>$user->name,
                'token'=>$token,
                'message'=>'Registered successfully'
            ]);
        
    

User.php:

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable

    use HasApiTokens, HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

cors.php:

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Cross-Origin Resource Sharing (CORS) Configuration
    |--------------------------------------------------------------------------
    |
    | Here you may configure your settings for cross-origin resource sharing
    | or "CORS". This determines what cross-origin operations may execute
    | in web browsers. You are free to adjust these settings as needed.
    |
    | To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
    |
    */

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

    'allowed_methods' => ['*'],

    'allowed_origins' => ['*'],

    'allowed_origins_patterns' => [],

    'allowed_headers' => ['*'],

    'exposed_headers' => [],

    'max_age' => 0,

    'supports_credentials' => true,

];

api.php:

<?php

use App\Http\Controllers\API\AuthController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;


Route::post('register',[AuthController::class,'register']);

frontends configurations.
App.js.
axios.defaults.baseURL="http://127.0.0.1:8000";
axios.defaults.headers.post['Content-Type'] = 'application/json';
axios.defaults.headers.post['Accept'] = 'application/json';

axios.defaults.withCredentials = true;```

eRegister.js.
import React, useState from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import axios from "axios";

class eRegister extends React.Component
    constructor(props) 
        super(props);
        this.state=
            name:"",
            email:"",
            password:""
        
    
    registerData=(event)=>
        const value = event.target.value;
        const name = event.target.name;
        this.setState(
            [name]:value
        )
    
    register=()=>
        console.log(this.state);
        axios.get('/sanctum/csrf-cookie').then(response => 
            axios.post('api/register').then(response=>

            )
        );
    
    render() 
        return(
            <div>
                <form>
                    <label>Name:</label><input type="text" name="name" onChange=this.registerData/>
                    <label>Email:</label><input type="text" name="email" onChange=this.registerData/>
                    <label>Password</label><input type="password" name="password" onChange=this.registerData/>
                    <button type="button" onClick=()=>this.register()>Register</button>
                </form>
            </div>
        )
    

export default eRegister;

【问题讨论】:

您是否将EnsureFrontendRequestsAreStateful 类添加到您的api 中间件组? 是的,我做到了,'api' =&gt; [ \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, 'throttle:api', \Illuminate\Routing\Middleware\SubstituteBindings::class, ], 【参考方案1】:

如果你使用 Laravel 作为 API。那么你不应该使用 CSRF 令牌。

CSRF 验证中间件是为 Web 路由设置的,而不是为 API 设置的。

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

        'api' => [
            'throttle:api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];

【讨论】:

laravel.com/docs/8.x/sanctum#spa-authentication

以上是关于反应前端中的 CSRF 令牌不匹配的主要内容,如果未能解决你的问题,请参考以下文章

反应形式 CSRF 安全

如何使用我的后端中使用的前端反应中的 Auth0 访问令牌

反应 + springboot csrf

用于反应前端的基于令牌的身份验证

csrf 令牌会在 laravel 中的每个请求上自动重新生成,这会导致生产服务器上的 csrf 令牌不匹配

cakephp3.7 测试中的 CSRF 令牌不匹配