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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 16:13:21