基于Djoser与JWT的Django认证系统实现是否安全?
Django + Djoser JWT 认证系统的安全问题与改进方案
你的核心担忧完全合理:当前实现中仅靠access token就能创建Django Session的逻辑存在严重安全隐患,一旦token被窃取,攻击者无需密码就能登录用户账号。下面具体分析问题并给出改进方案:
核心风险点
- 前端传递用户数据不可信:后端
auth视图依赖前端传入的user字段(包含id、username、email)查询用户,前端可随意篡改这些数据,只要携带有效access token,就能登录任意匹配该信息的用户。 - JWT与Django Session混合使用冗余且危险:用JWT获取用户信息后再同步创建Django Session,完全没必要,反而引入双重认证冲突和额外攻击面。
- Token存储不安全:
- Access Token存在可读写Cookie中(未设置
HttpOnly),XSS攻击可轻易窃取token。 - Refresh Token同样未设置
HttpOnly,一旦被窃取,攻击者可无限刷新获取新的access token。
- Access Token存在可读写Cookie中(未设置
- 前端冗余的token验证流程:每次页面加载都调用
verify和authorize接口,既增加服务器负担,又可能让token暴露在更多请求中,提升泄露风险。
具体改进方案
1. 停止混合认证,统一用JWT流程
直接使用Djoser自带的JWT认证能力,放弃手动同步Django Session的逻辑:
- 所有需要认证的接口,后端通过JWT中间件自动验证请求头或Cookie中的token。
- 无需前端手动同步用户到Session,后端直接通过
request.user获取当前认证用户。
2. 优化Token存储安全
- Access Token:配置Djoser将其存储在
HttpOnly、Secure、SameSite=Strict的Cookie中,前端无法直接读取,避免XSS窃取。 - Refresh Token:同样存储在
HttpOnly的Cookie中,仅允许后端读取和验证,前端只需要在请求返回401时调用刷新接口。
3. 简化前端逻辑
去掉冗余的verify、authorize、auth函数,简化登录和登出流程:
// 登录请求 $.post("/auth/jwt/create/", $(this).serialize()) .done(function() { // 后端已将token写入HttpOnly Cookie,直接跳转首页 window.location.href = "/"; }) .fail(function() { alert("登录失败,请检查账号密码"); }); // 登出请求 function logout() { $.post("/auth/jwt/logout/", { "csrfmiddlewaretoken": $("meta[name='csrf-token']").attr("content") }) .done(function() { // 后端清除Cookie后跳转登录页 window.location.href = "/login/"; }); } // 页面加载时无需手动验证token,后端接口会自动处理认证
4. 后端配置与视图优化
配置Djoser与JWT(settings.py)
DJOSER = { "LOGIN_FIELD": "username", # Access Token Cookie配置 "JWT_AUTH_COOKIE": "access_token", "JWT_AUTH_COOKIE_SECURE": True, "JWT_AUTH_COOKIE_HTTPONLY": True, "JWT_AUTH_COOKIE_SAMESITE": "Strict", # Refresh Token Cookie配置 "JWT_AUTH_REFRESH_COOKIE": "refresh_token", "JWT_AUTH_REFRESH_COOKIE_SECURE": True, "JWT_AUTH_REFRESH_COOKIE_HTTPONLY": True, "JWT_AUTH_REFRESH_COOKIE_SAMESITE": "Strict", } REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ( "rest_framework_simplejwt.authentication.JWTAuthentication", ), # 全局配置需要认证的接口,或在视图中单独设置 "DEFAULT_PERMISSION_CLASSES": ( "rest_framework.permissions.IsAuthenticated", ) }
简化后端视图
废弃原有的auth视图,直接通过JWT中间件获取用户:
from rest_framework.decorators import api_view from rest_framework.response import Response @api_view(["GET"]) def user_me(request): # request.user由JWT中间件自动验证并填充 return Response({ "id": request.user.id, "username": request.user.username, "email": request.user.email })
5. 登出逻辑增强
Djoser默认的JWT登出只会清除前端Cookie,建议额外实现refresh token失效逻辑:
- 将refresh token存储到数据库中,登出时标记为无效,刷新时检查token有效性。
- 或设置较短的refresh token有效期,降低被窃取后的风险。
内容的提问来源于stack exchange,提问作者bur
相关产品推荐
相关产品推荐

