You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django REST+React中CSRFToken与Knox认证的密码修改问题排查

解决Django REST + Knox Token认证下密码修改接口的CSRF与重定向问题

看起来你遇到的核心矛盾是:Django自带的password_change视图是为传统session认证的Web应用设计的,而你的项目采用的是Knox Token的无状态REST认证体系,两者不兼容导致了一系列问题。下面逐个解决你的三个问题:


核心解决方案:替换为DRF风格的密码修改API视图

首先要抛弃Django Auth自带的password_change视图,改用DRF实现自定义的密码修改接口,适配Knox Token认证。

1. 在views.py中添加自定义密码修改视图

from django.contrib.auth import update_session_auth_hash
from rest_framework import status, generics
from rest_framework.permissions import IsAuthenticated
from knox.auth import TokenAuthentication

class PasswordChangeAPI(generics.UpdateAPIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = (IsAuthenticated,)
    
    def update(self, request, *args, **kwargs):
        user = request.user
        old_password = request.data.get('old_password')
        new_password1 = request.data.get('new_password1')
        new_password2 = request.data.get('new_password2')
        
        # 验证旧密码正确性
        if not user.check_password(old_password):
            return Response({"old_password": ["旧密码输入错误"]}, status=status.HTTP_400_BAD_REQUEST)
        
        # 验证新密码一致性
        if new_password1 != new_password2:
            return Response({"new_password2": ["两次输入的新密码不一致"]}, status=status.HTTP_400_BAD_REQUEST)
        
        # 更新密码
        user.set_password(new_password1)
        user.save()
        
        # 注意:Knox Token认证不需要更新session,这行是给session认证用的,可注释
        # update_session_auth_hash(request, user)
        
        return Response({"detail": "密码修改成功"}, status=status.HTTP_200_OK)

2. 更新urls.py,替换默认的auth路由

把原来的path('', include('django.contrib.auth.urls')),替换为自定义接口的路由:

urlpatterns = [
    # ... 其他原有路由保持不变
    path('password-change/', PasswordChangeAPI.as_view(), name='password_change'),
    # 删除或注释掉原来的include('django.contrib.auth.urls')
]

逐个解决你的具体问题

问题1:可浏览API调用password_change重定向到登录页

现在使用DRF的自定义视图后,可浏览API会支持Knox Token认证:

  • 打开可浏览API页面,点击右上角的Authorize按钮
  • 输入格式为 Token <你的Knox Token值> 的内容,完成认证
  • 再调用/accounts/password-change/接口,就会正常返回JSON响应,不会重定向到登录页

问题2:Postman调用接口因CSRF报错

DRF对非session类的认证(比如Knox Token)会自动跳过CSRF验证,现在你只需要:

  • 在Postman的请求Headers中添加 Authorization: Token <你的Knox Token>
  • 请求Body中传入old_password、new_password1、new_password2的JSON数据
  • 直接发送POST请求即可,不会再出现CSRF相关报错

问题3:React前端的CSRF与重定向问题

解决重定向问题

自定义视图返回的是JSON响应,不再是Django自带的重定向,所以前端提交后不会跳转到其他页面,你可以在then回调里处理成功逻辑(比如提示用户密码修改成功)。

解决CSRF Token获取问题

因为我们用的是Token认证,不需要CSRF保护(CSRF是针对session认证的攻击场景设计的,Token认证是无状态的,每个请求都携带Token,天然避免CSRF风险),所以你可以:

  • 去掉前端Axios中关于CSRF的配置(xsrfCookieName、xsrfHeaderName这些)
  • 不需要再通过react-cookie获取csrftoken

修正前端代码的小bug

你的ChangePassword.js中输入框的value绑定错误,会导致输入内容无法正确更新,修正如下:

// 修正输入框的value绑定
<input type="password" name="old_password" value={this.state.credentials.old_password} onChange={this.inputChanged} onKeyPress={this.pressedEnter}/><br/>
<input type="password" name="new_password1" value={this.state.credentials.new_password1} onChange={this.inputChanged} onKeyPress={this.pressedEnter}/><br/>
<input type="password" name="new_password2" value={this.state.credentials.new_password2} onChange={this.inputChanged} onKeyPress={this.pressedEnter}/><br/>

同时修正Axios的baseURL,指向你的Django API地址:

// 在Index.js中修改
axios.defaults.baseURL = 'http://127.0.0.1:8000/accounts/';

内容的提问来源于stack exchange,提问作者Onursezn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 10:37:53