正确获取和设置 csrf 令牌

问题描述

我正在尝试创建一个使用 flask_corsflask_wtf 的简单应用程序。但是,当我使用 flask_wtf 时,当我尝试发送 POST 请求时,会收到一个响应,说缺少 CSRF 令牌

这是我的后端应用程序(在端口 3080 上运行):

__init__.py

from flask import Flask
from flask_cors import CORS
from flask_wtf.csrf import CSRFProtect

cors = CORS()
csrf = CSRFProtect()

def create_app(config):

    app = Flask(__name__,instance_relative_config=False)

    app.config['TESTING'] = True 
    app.config['DEBUG'] = True
    app.config['JSON_SORT_KEYS'] = False
    app.config['SECRET_KEY'] = 'You will never guess me!'
    app.config['SESSION_COOKIE_HTTPONLY']= True
    app.config['REMEMBER_COOKIE_HTTPONLY'] = True
    app.config['SESSION_COOKIE_SAMESITE'] = 'Strict'
    
    cors.init_app(app)
    csrf.init_app(app)

    with app.app_context():

        from app.views.sanity_bp import sanity_bp

        app.register_blueprint(sanity_bp,url_prefix='/api/sanity')

        return app

sanity_bp.py

from flask import Blueprint,jsonify,request
from flask_cors import cross_origin
from flask_wtf.csrf import generate_csrf

sanity_bp = Blueprint('sanity_bp',__name__)

@sanity_bp.route('/get/csrf',methods=['GET'])
def get_csrf():
    return jsonify({'csrf_token': generate_csrf()}),200

@sanity_bp.route('/post',methods=['POST'])
@cross_origin()
def post():
    return jsonify('sanity: post request'),200

我使用 get_csrf() 方法获取 CSRF 令牌。

前端(运行在8080端口)如下:

<template>
  <div>
    Hello stack <b>overflow</b>!
  </div>
</template>

<script>
import axios from 'axios';

const API = axios.create({
  baseURL: 'http://127.0.0.1:3080/api',});

const csrf = () => {
  API
    .get('/sanity/get/csrf',{ credentials: 'same-origin' })
    .then((res) => {
      API.defaults.headers.post['x-csrf-token'] = res.data.csrf_token;
    })
    .catch((err) => {
      console.log('err = ',err);
    });
};

export default {
  name: 'app',methods: {
    sanity() {
      API
        .post('/sanity/post',{ message: 'ping' })
        .then((res) => {
          console.log('res.data = ',res.data);
        })
        .catch((error) => {
          console.error('error = ',error);
        });
    },},created() {
    csrf();
    this.sanity();
  },};
</script>

因此,当调用 created() 方法时,我从后端获取 CSRF 令牌并将其设置为 x-csrf-token 函数标头中的 API 值。

但是,当我在 sanity() 方法中使用 POST 请求时,我收到 400 错误,指出未设置 CSRF 令牌。此外,x-csrf-token 键在请求标头中不可见。为什么不,请问我在获取令牌时哪里出错了?

解决方法

您在前端的 csrf 函数是异步的,您需要等到它完成后才能在 this.sanity(); 函数中创建 created。您可以使用 async/await

...
async created() {
  await csrf();
  await this.sanity();
},...