如何关闭Django auth中PasswordResetView的CSRF校验?
问题解决:Django类视图中@csrf_exempt装饰post方法无效的问题
原因分析
直接在类视图的post方法上添加@csrf_exempt装饰器无法绕过CSRF校验,因为Django的CsrfViewMiddleware会在视图的具体方法(如post)执行之前进行校验,装饰单个方法无法影响中间件的校验流程。
解决方案
有两种可靠的方式可以让类视图跳过CSRF校验:
方案1:在URL配置中装饰as_view()
修改urls.py,将csrf_exempt直接装饰在视图的as_view()方法上:
from django.views.decorators.csrf import csrf_exempt from . import views urlpatterns = [ # 其他URL配置... path('reset_password', csrf_exempt(views.ResetPasswordView.as_view()), name='password_reset'), ]
方案2:使用method_decorator装饰类的dispatch方法
dispatch是类视图处理所有请求的入口方法,装饰它可以让整个视图跳过CSRF校验,有两种写法:
写法A:装饰整个类
from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt from django.contrib.auth.views import PasswordResetView from django.contrib.messages.views import SuccessMessageMixin @method_decorator(csrf_exempt, name='dispatch') class ResetPasswordView(SuccessMessageMixin, PasswordResetView): template_name = 'users/password_reset.html' email_template_name = 'users/password_reset_email.html' subject_template_name = 'users/password_reset_subject' success_message = "We've emailed you instructions for setting your password, " \ "if an account exists with the email you entered. You should receive them shortly." \ " If you don't receive an email, " \ "please make sure you've entered the address you registered with, and check your spam folder." success_url = reverse_lazy('users-home') def post(self, request, *args, **kwargs): # 修正:普通Django视图无request.data,需手动解析JSON请求 import json if request.content_type == 'application/json': data = json.loads(request.body) # 注意你的curl请求发送的是username字段,不是email email = data.get('email') or data.get('username') else: email = request.POST.get('email') try: if User.objects.get(email=email).active: print("email: %s " % email) return super().post(request, *args, **kwargs) except User.DoesNotExist: # 捕获特定异常,避免捕获所有异常 return super().post(request, *args, **kwargs)
写法B:装饰dispatch方法本身
class ResetPasswordView(SuccessMessageMixin, PasswordResetView): # 类属性... @method_decorator(csrf_exempt) def dispatch(self, request, *args, **kwargs): return super().dispatch(request, *args, **kwargs) # post方法...
额外注意事项
- 你的curl请求发送的是
{"username":"abc@dev.com"},但代码中使用request.data.get('email'),而普通Django视图没有request.data属性(这是Django REST Framework视图的特性),需要手动解析JSON请求体,如上文中的代码修正。 - 避免捕获所有异常(
except:),建议捕获User.DoesNotExist,这样不会掩盖其他潜在错误。
内容的提问来源于stack exchange,提问作者Dave
相关产品推荐
相关产品推荐

