Django DRF Token认证Redis缓存优化实现求助
DRF Token认证Redis缓存优化方案
问题背景
用DRF做Token认证时,每次请求都会查数据库验证Token并拉取用户信息,想通过Redis缓存Token和用户的映射关系,减少数据库查询次数、提升接口响应速度。前端是移动端,只能用Token认证,不用切换Session。
实现步骤
1. 自定义Token认证类
重写DRF自带的TokenAuthentication,让它优先从Redis读缓存,缓存没命中再查数据库,同时把查询结果存入缓存。
在你的app目录下新建authentication.py文件,写入以下代码:
from rest_framework.authentication import TokenAuthentication from rest_framework.authtoken.models import Token from django_redis import get_redis_connection from django.contrib.auth import get_user_model User = get_user_model() class CachedTokenAuthentication(TokenAuthentication): def authenticate_credentials(self, key): # 获取Redis连接 redis_conn = get_redis_connection('default') cache_key = f"token:{key}" # 先从缓存取用户ID user_id = redis_conn.get(cache_key) if user_id is not None: try: user = User.objects.get(pk=int(user_id)) return (user, key) except User.DoesNotExist: # 缓存存在但用户已删除,清理无效缓存 redis_conn.delete(cache_key) # 缓存没命中,走原生逻辑查数据库 try: token = Token.objects.select_related('user').get(key=key) except Token.DoesNotExist: return None if not token.user.is_active: return None # 将Token与用户ID绑定存入缓存,设置7天过期(可根据业务调整时长) redis_conn.setex(cache_key, 60*60*24*7, token.user.pk) return (token.user, token)
2. 修改settings.py的认证配置
把原来的TokenAuthentication替换成自定义的缓存认证类:
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES' : ( '你的app名称.authentication.CachedTokenAuthentication', # 替换成实际的app路径 ), }
3. 更新登录视图,同步写入缓存
用户登录生成/获取Token时,直接把Token和用户ID的关系写入Redis,避免第一次请求还是查数据库:
from rest_framework.authtoken.models import Token from django.contrib.auth import authenticate from django_redis import get_redis_connection @api_view(['POST']) @permission_classes([AllowAny]) def UserLogin(request): if request.method=='POST': username = request.data.get('username') password = request.data.get('password') user = authenticate(username=username, password=password) if user is not None: token, created = Token.objects.get_or_create(user=user) # 写入Redis缓存 redis_conn = get_redis_connection('default') cache_key = f"token:{token.key}" # 保持和认证类一致的过期时间 redis_conn.setex(cache_key, 60*60*24*7, user.pk) return Response({'token': token.key,'name':user.fname+' '+user.lname, 'phone':user.phone,'username':user.username,'email':user.email}) else: return Response({'error': 'Invalid credentials'})
4. 处理Token失效场景
当用户修改密码、账号被禁用/删除时,要同步清理对应的Token和缓存,避免脏数据:
示例:用户修改密码后清理Token与缓存
from rest_framework.authtoken.models import Token from django_redis import get_redis_connection def change_password(request): # 这里写密码修改的业务逻辑... # 修改成功后,删除用户的Token和对应缓存 user = request.user # 删除数据库中的Token Token.objects.filter(user=user).delete() # 删除Redis中的缓存(如果能拿到当前请求的Token) if request.auth: redis_conn = get_redis_connection('default') redis_conn.delete(f"token:{request.auth.key}") return Response({'message': '密码修改成功'})
注意事项
- 缓存过期时间可根据业务需求调整,比如和Token的有效期对齐,或者设置固定时长
- 用户状态变更(如禁用、删除)时,一定要同步清理缓存,避免缓存的用户信息和数据库不一致
- 自定义认证类中,缓存命中后仍会查询一次用户(验证是否活跃),如果想进一步优化,可以把用户的活跃状态也存入缓存,但要注意状态变更时同步更新
内容的提问来源于stack exchange,提问作者varun_k_21
相关产品推荐
相关产品推荐

