在开启 CSRF 保护的情况下使用axios发生post请求,报错 400 (BAD REQUEST)

首先在创建app的时候开启了CORS和CSRF保护
main.py

def create_app():
    app = Flask(__name__)
    # 跨域访问
    CORS(app, resources={r'/*': {'origins': '*'}})
    # 改变jinja2模板
    app.jinja_env.variable_start_string = '{['
    app.jinja_env.variable_end_string = ']}'
    app.config.from_object(config)

    db.init_app(app)
    # csrf保护
    csrf.init_app(app)

我已经在html中添加了meta标签生成CSRF令牌,并且index.html中并没有表单,但在axios发送ajax post请求的时候出现Failed to load resource: the server responded with a status of 400 (BAD REQUEST)错误

备注:我尝试了在idnex.html中添加和 <input type=“hidden” name=“csrf_token” value="{{ csrf_token() }},仍然没有奏效

index.html

 <meta name="csrf-token" content="{[csrf_token()]}">
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-sm" style="padding-top: 20px" id="app">
            <div class="shadow p-3 mb-5 bg-white rounded" v-for="question,index in questions"
                 style="width: 50%;margin: auto">
                <label>第{{ index + 1 }}题:{{ question.subject }}</label><br>
                <li :class="{checked:question.answer_1==selected[index]}"
                    @click="changeSelected(question.answer_1,index)">
                    A、 {{ question.answer_1 }}
                </li>

index.js

submitAnswers() {
    // 将用户选择的答案发送到后台;
    axios.post('/result/', {
        selected: this.selected
    })
        .then(function (response) {
            var status = response.data.status;
            // alert(status)
            if (status == 'success') {
                window.location.href = '/score/'
            } else {
                alert("Error!")
            }
        })
        .catch(function (error) {
            alert("Error!");
        });
}

所以我必须在视图中使用’@csrf.exempt '装饰器来关闭CSRF保护才能避免报错

views.py

@csrf.exempt
@bp.route('/result/', methods=['POST'])
def result():
    if request.method == 'POST':
        try:
            record = Answer_record.query.filter_by(user_id=g.user.id).order_by(
                Answer_record.start_time.desc()).first()

如何在不使用’@csrf.exempt '装饰器的情况下避免报错呢?

我尝试了参考https://codekitchen.community/t/topic/849,但并没有奏效

对于 AJAX 请求,CSRF token 应该放到 header 的 X-CSRFToken 字段里:

<script type="text/javascript">
    axios.defaults.headers.common["X-CSRFToken"] = "{{ csrf_token() }}";
</script>

https://flask-wtf.readthedocs.io/en/1.0.x/csrf/#javascript-requests

1 个赞

谢谢,按照方法已经解决了 :hugs: