直接使用djangorestframework-simplejwt而非手写jwt逻辑,因其已完备支持exp/iat/nbf校验、密钥轮换、黑名单机制,并持续适配django版本;手写易遗漏关键安全细节。

为什么直接用 djangorestframework-simplejwt 而不是手写 JWT 逻辑?
手写签发、校验、刷新逻辑容易漏掉关键细节:比如 exp 校验未强制、iat 和 nbf 忽略、密钥轮换无支持、黑名单机制缺失。社区方案已覆盖这些边界,且持续适配 Django 版本变更。直接集成 djangorestframework-simplejwt 是更稳妥的选择。
安装后需在 settings.py 中配置:
INSTALLED_APPS += ['rest_framework_simplejwt']<br><br>REST_FRAMEWORK = {<br> 'DEFAULT_AUTHENTICATION_CLASSES': [<br> 'rest_framework_simplejwt.authentication.JWTAuthentication',<br> ],<br>}<br><br>from datetime import timedelta<br>SIMPLE_JWT = {<br> 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=15),<br> 'REFRESH_TOKEN_LIFETIME': timedelta(days=7),<br> 'ROTATE_REFRESH_TOKENS': True,<br> 'BLACKLIST_AFTER_ROTATION': True,<br>}
如何让登录接口返回 access + refresh token 并支持前端存储?
默认的 TokenObtainPairView 只返回 access 和 refresh 字段,但前端通常需要明确字段名、HTTP 状态码和可选的用户信息。建议继承并重写响应结构:
from rest_framework_simplejwt.views import TokenObtainPairView<br>from rest_framework_simplejwt.serializers import TokenObtainPairSerializer<br><br>class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):<br> def validate(self, attrs):<br> data = super().validate(attrs)<br> data['user_id'] = self.user.id<br> data['email'] = self.user.email<br> return data<br><br>class CustomTokenObtainPairView(TokenObtainPairView):<br> serializer_class = CustomTokenObtainPairSerializer
路由中注册该视图,前端调用后即可拿到含用户基础信息的 token 响应。注意:不要把敏感字段(如密码哈希、权限列表)塞进 token payload,应在后续请求中按需查库。
刷新 token 时遇到 Token is blacklisted 怎么办?
这个错误通常出现在启用了 ROTATE_REFRESH_TOKENS=True 后,客户端重复使用旧 refresh token 请求新 access token。原因包括:
- 前端未及时用新返回的
refresh替换本地存储的旧值 - 并发请求中多个请求同时用同一个
refresh触发了黑名单写入 -
BLACKLIST_AFTER_ROTATION开启后,旧 token 立即失效,无法二次使用
解决方式:
- 确保前端在每次成功刷新后,用响应体中的新
refresh覆盖本地存储 - 对刷新请求做防抖或串行化处理(例如用 Promise 链或锁机制)
- 若业务允许,可临时关闭
BLACKLIST_AFTER_ROTATION,但会牺牲安全性
如何在非 API 视图(如通用类视图或模板视图)中获取当前 JWT 用户?
JWTAuthentication 默认只作用于 DRF 的 APIView 及其子类,普通 View 或模板视图不会自动解析 Authorization header。不能依赖 request.user,必须手动解码:
from rest_framework_simplejwt.tokens import AccessToken<br>from django.contrib.auth.models import User<br><br>def my_view(request):<br> auth_header = request.META.get('HTTP_AUTHORIZATION')<br> if not auth_header or not auth_header.startswith('Bearer '):<br> return HttpResponseForbidden()<br> try:<br> token = auth_header.split(' ')[1]<br> validated_token = AccessToken(token)<br> user_id = validated_token['user_id']<br> user = User.objects.get(id=user_id)<br> except Exception:<br> return HttpResponseForbidden()<br> # 继续业务逻辑
注意:AccessToken 不校验 refresh token;若需支持双 token 场景,应统一用 RefreshToken 类并调用其 access_token 属性;生产环境务必捕获 TokenError、InvalidToken 等具体异常,而非宽泛的 Exception。
JWT 的无状态本质意味着所有校验都在内存中完成,不查数据库——但这也导致你无法在 token 有效期内主动使某个用户登出,除非引入 Redis 黑名单或缩短 ACCESS_TOKEN_LIFETIME。这点常被忽略,直到遇到强制下线需求才意识到代价。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











