Django新增@csrf_exempt装饰视图仍报CSRF验证失败如何排查
Django新增@csrf_exempt接口返回CSRF校验失败排查方案
排查前先确认服务已经完全重启加载了最新代码,避免因代码未更新做无用排查,之后按优先级从高到低检查以下问题:
- 验证请求是否到达目标视图
在getcodetodeleteaccount函数第一行加打印日志或断点,调用接口时看是否触发。如果完全没进函数,说明是路由匹配错误:检查项目所有生效的url配置,是否有正则更宽泛的路由(比如r'getcode\w*$'这类)排在你新增的url(r'getcodetodeleteaccount$', websvc2_account.getcodetodeleteaccount)前面,提前把请求拦截到了其他未加CSRF豁免的视图上,调整路由顺序或者收窄冲突路由的正则即可。 - 验证@csrf_exempt装饰器是否生效
Django会给加了@csrf_exempt的视图附加csrf_exempt = True的标记,在urls.py对应路由位置加一行打印代码,启动服务时看输出:
如果输出为print("目标视图CSRF豁免状态:", getattr(websvc2_account.getcodetodeleteaccount, 'csrf_exempt', False))False,说明装饰器没有正确生效,对应排查三个方向:- 核对代码,确认
@csrf_exempt确实装饰在getcodetodeleteaccount函数上,没有误加到相邻的其他函数上。 - 检查装饰器顺序:如果该函数还叠加了其他装饰器(比如
@login_required、@require_POST、自定义权限校验装饰器等),@csrf_exempt必须放在所有装饰器的最外层(也就是所有装饰器最上方的位置),否则外层装饰器返回的包装函数会丢失CSRF豁免标记。错误和正确写法示例:
如果不想调整装饰器顺序,可以给所有自定义装饰器加上# 错误写法:@login_required在外层,返回的包装函数无豁免标记 @login_required @csrf_exempt def getcodetodeleteaccount(request): ... # 正确写法:@csrf_exempt在外层,标记可被CSRF中间件识别 @csrf_exempt @login_required def getcodetodeleteaccount(request): ...@functools.wraps(原函数),自动携带原函数的所有属性,避免标记丢失。 - 检查模块导入逻辑:排查是否存在循环导入、
websvc2_account模块下有重名函数、加载了旧版本pyc缓存的情况,确保路由引用的就是你编写的加了装饰器的目标函数。
- 核对代码,确认
- 排查自定义中间件干扰
如果前两步都确认无问题,检查项目自定义的中间件,是否有中间件在CsrfViewMiddleware之后执行,强制触发了CSRF校验、忽略了视图的豁免标记。这种情况概率极低,毕竟其他同模块加了@csrf_exempt的老接口都能正常运行,只有新接口出问题基本不会是这个原因。
内容的提问来源于stack exchange,提问作者HansG600
相关产品推荐
相关产品推荐

