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

Django如何生成唯一用户Token?DRF Token登录网关问题求助

问题解答

嘿,我来帮你理清这个问题的解决思路,分两部分给你说明:

1. DRF Token 是否每个用户唯一?

没错,DRF 自带的 Token 模型(来自 rest_framework.authtoken.models)默认和用户模型是一对一绑定的——每个用户只会对应一个 Token,除非你手动硬给同一个用户创建多个(这完全没必要,反而不安全),所以正常情况下每个用户的 Token 是唯一的。

不过这里要敲个重点:你在自定义的 MyUser 模型里加了自己的 token 字段,这和 DRF 自带的 Token 是完全分开的两个东西!DRF 的 Token 存在单独的 authtoken_token 数据库表中,而你自己的 token 字段是存在 MyUser 表的,两者没有任何关联。这很可能就是你遇到「MyUser匹配查询不存在」错误的核心原因——你用 DRF 返回的 Token(来自 DRF 的 Token 表)去查 MyUser 的 token 字段,当然找不到对应的用户啦!

2. 如何生成 Token 并适配你的登录网关?

根据你的需求,有两种靠谱方案,推荐优先用 DRF 自带的 Token 系统,省心又安全:

方案一:用 DRF 自带的 Token 系统(推荐)

第一步:先配置好 DRF Token 认证

  1. 打开 settings.py,把 DRF 的 Token 应用加进去:
INSTALLED_APPS = [
    # ... 你已有的其他应用
    'rest_framework',
    'rest_framework.authtoken',  # 新增这一行
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
        # 如果你还需要其他认证方式(比如session),可以继续加
    ]
}
  1. 执行数据库迁移,创建 DRF 用来存 Token 的表:
python manage.py migrate

第二步:为用户生成 Token

有两种方式生成:

  • 新用户自动生成:用 Django 信号量实现,在你的 MyUser 模型文件(比如 business_accounts/models/my_user.py)里加这段代码:
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
from django.conf import settings

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
    # 当用户被创建时,自动生成对应的Token
    if created:
        Token.objects.create(user=instance)
  • 给已有用户补生成 Token:如果是已经存在的用户,直接在 Django shell 里跑:
from rest_framework.authtoken.models import Token
from business_accounts.models.my_user import MyUser

user = MyUser.objects.get(user_id=52)  # 替换成你的用户ID
token, created = Token.objects.get_or_create(user=user)
print(token.key)  # 这个就是用户的Token,和你之前DRF返回的格式一致

第三步:修改你的登录网关视图

现在要从 DRF 的 Token 表里查询用户,而不是查 MyUser 的 token 字段,还要加异常处理避免崩溃:

from django.contrib.auth import login
from django.core.urlresolvers import reverse
from django.views.generic import View
from django.http import HttpResponseRedirect
from rest_framework.authtoken.models import Token  # 导入DRF的Token模型

class UrlGatewayLogin(View):
    def get(self, request, **kwargs):
        page_group = kwargs.get('page_group')
        token_key = request.GET.get('token')
        
        try:
            # 通过Token的key找到对应的Token记录,再关联到用户
            token = Token.objects.get(key=token_key)
            user = token.user
        except Token.DoesNotExist:
            # Token无效的话,跳转到登录页或者错误页,这里你自己调整
            return HttpResponseRedirect(reverse('login'))
        
        # 必须指定backend才能正常登录
        user.backend = 'django.contrib.auth.backends.ModelBackend'
        login(request, user)
        return HttpResponseRedirect(reverse('dashboard', args=(page_group, )))

方案二:用你自定义的 MyUser.token 字段

如果你坚持要用自己加的 token 字段,那得确保 Token 正确生成并保存到用户实例里:

第一步:生成并保存自定义 Token

用 Python 的 secrets 模块生成安全的随机字符串(比普通随机方法更安全),同样可以用信号量自动生成:

from django.db.models.signals import post_save
from django.dispatch import receiver
import secrets
from business_accounts.models.my_user import MyUser

@receiver(post_save, sender=MyUser)
def create_custom_token(sender, instance=None, created=False, **kwargs):
    if created and not instance.token:
        # 生成40位的随机Token(和DRF默认的Token长度一致)
        instance.token = secrets.token_hex(20)
        instance.save()

要是给已有用户补生成,就手动跑:

import secrets
from business_accounts.models.my_user import MyUser

user = MyUser.objects.get(user_id=52)
user.token = secrets.token_hex(20)
user.save()

第二步:修复视图的查询逻辑

一定要加异常处理,避免因为无效 Token 直接抛错:

from django.contrib.auth import login
from django.core.urlresolvers import reverse
from django.views.generic import View
from django.http import HttpResponseRedirect
from business_accounts.models.my_user import MyUser

class UrlGatewayLogin(View):
    def get(self, request, **kwargs):
        page_group = kwargs.get('page_group')
        token = request.GET.get('token')
        
        try:
            user = MyUser.objects.get(token=token)
        except MyUser.DoesNotExist:
            # Token无效时的处理,比如跳登录页
            return HttpResponseRedirect(reverse('login'))
        
        user.backend = 'django.contrib.auth.backends.ModelBackend'
        login(request, user)
        return HttpResponseRedirect(reverse('dashboard', args=(page_group, )))

最后再复盘下你之前的错误原因

你用 DRF 返回的 Token 是 DRF 自带 Token 表中的值,但你的 MyUser.token 字段根本没存这个值,所以当你用这个 Token 去查 MyUser 时,自然找不到对应的用户,就抛出了「匹配查询不存在」的错误。只要把查询逻辑对应到正确的 Token 来源(要么 DRF 的 Token 表,要么自己的 MyUser.token 字段),问题就解决啦!


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 03:57:37