Django视图中如何正确实现CSRF验证?解决403禁止访问问题
问题解答
核心原因
你出现403错误的根本问题并非CsrfViewMiddleware和@csrf_protect冲突——默认项目都会启用CsrfViewMiddleware全局保护,@csrf_protect仅用于给被全局排除的视图单独添加保护,二者共存不会直接引发错误。真正的问题是你硬编码的表单里没有包含CSRF令牌字段:只要开启了CSRF保护(无论全局中间件还是装饰器),POST请求必须携带合法的CSRF令牌才能通过验证。之前用模板时添加了{% csrf_token %},自动生成了令牌字段,所以功能正常。
关于你的疑问:可以在视图内处理CSRF验证,不一定必须用模板
只要能确保POST请求携带CSRF令牌,不用模板也可行。下面提供两种解决方案:
方案1:手动在视图生成CSRF令牌并插入表单
先导入CSRF令牌生成函数,再在返回表单时将令牌作为隐藏字段插入:
from django.middleware.csrf import get_token from django.shortcuts import redirect, reverse from django.http import HttpResponse from .models import Group @csrf_protect # 若已启用全局CsrfViewMiddleware,该装饰器可省略 def create_group(request): if request.method == "POST": Group.objects.create(**{key: request.POST[key] for key in request.POST}) return redirect(reverse("groups:groups")) # 生成当前请求的CSRF令牌 csrf_token = get_token(request) # 将令牌字段插入表单末尾 form_html = create_group_form.replace( "</form>", f'<input type="hidden" name="csrfmiddlewaretoken" value="{csrf_token}"></form>' ) return HttpResponse(form_html)
方案2:改用Django模板(推荐)
这是更规范的做法,将表单内容放到模板文件(如create_group_form.html)中:
<form method="POST"> {% csrf_token %} <label for="course">Course:</label><br> <input type="text" id="course" name="course"><br><br> <!-- 其余表单字段保持不变 --> <input type="submit" value="Submit"> </form>
修改视图,用render返回模板:
from django.shortcuts import render, redirect, reverse from .models import Group # 全局已启用CsrfViewMiddleware时,无需@csrf_protect def create_group(request): if request.method == "POST": Group.objects.create(**{key: request.POST[key] for key in request.POST}) return redirect(reverse("groups:groups")) return render(request, "create_group_form.html")
额外说明
如果你的settings.py中已经启用了django.middleware.csrf.CsrfViewMiddleware(默认开启),@csrf_protect装饰器属于冗余配置,去掉它不影响CSRF保护效果,只要表单包含令牌字段即可。
内容的提问来源于stack exchange,提问作者Алексей Василенко
相关产品推荐
相关产品推荐

