Django(DRF)中使用django-rest-knox为非用户模型实例生成令牌的方法
解决方案
django-rest-knox默认提供的AuthToken模型内置了指向Django默认User模型的非空外键约束,所以直接传入非User模型实例创建令牌必然触发字段校验错误。你可以通过两种方案实现需求:
方案1:自定义Knox令牌模型(推荐,灵活度最高)
这种方法完全修改底层令牌的关联逻辑,支持同时兼容用户和其他模型实例的令牌生成:
- 首先在项目
settings.py中添加配置,指定自定义令牌模型路径,同时禁用knox默认迁移:
# settings.py INSTALLED_APPS = [ # ... 其他应用 # 把knox从INSTALLED_APPS里移除,避免加载默认迁移 # 'knox', ] # 替换为你自己的应用名+自定义模型名 KNOX_MODEL = 'your_app_name.CustomAuthToken'
- 在你的应用中继承Knox的抽象令牌基类编写自定义模型,添加你需要关联的其他模型外键:
# your_app_name/models.py from django.db import models from django.core.exceptions import ValidationError from knox.models import AbstractAuthToken # 替换为你要关联的非User模型 from your_app_name.models import YourOtherModel class CustomAuthToken(AbstractAuthToken): # 保留user外键,设置为允许空,兼容原有用户令牌逻辑 user = models.ForeignKey( "auth.User", on_delete=models.CASCADE, null=True, blank=True, related_name="auth_tokens" ) # 新增你要关联的其他模型外键 your_other_instance = models.ForeignKey( YourOtherModel, on_delete=models.CASCADE, null=True, blank=True, related_name="auth_tokens" ) # 增加校验逻辑,确保令牌至少关联一个实例 def clean(self): super().clean() if self.user is None and self.your_other_instance is None: raise ValidationError("令牌必须关联用户或其他业务实例")
- 执行
makemigrations和migrate生成自定义表结构,之后就可以直接为非User实例生成令牌:
from your_app_name.models import CustomAuthToken # 为非User实例生成令牌,返回值为(令牌对象,明文令牌字符串) token_obj, token_str = CustomAuthToken.objects.create(your_other_instance=your_instance)
- 配套自定义认证类,适配非User实例的认证逻辑:
# your_app_name/auth.py from knox.auth import TokenAuthentication class CustomKnoxAuthentication(TokenAuthentication): def authenticate_credentials(self, key): user, token = super().authenticate_credentials(key) # 如果令牌关联的是业务实例,直接返回实例替代用户 if token.your_other_instance: return (token.your_other_instance, token) return (user, token)
之后在视图或全局配置中使用这个自定义认证类即可。
方案2:虚拟用户绑定(低侵入,适合小需求)
如果你不想修改Knox的底层逻辑,可以给每个需要生成令牌的非User实例绑定一个专属的无权限虚拟用户:
- 在User模型中添加标识字段,区分正常用户和虚拟绑定用户:
# 如果你用的是自定义User模型 class User(AbstractUser): is_virtual = models.BooleanField(default=False) # 存储关联的非User实例ID bound_instance_id = models.IntegerField(null=True, blank=True) # 存储关联的模型类型 bound_instance_type = models.CharField(max_length=50, null=True, blank=True)
- 生成令牌时,使用对应绑定的虚拟用户创建即可,认证时再根据虚拟用户的关联字段查询对应的业务实例。
内容的提问来源于stack exchange,提问作者Irfan wani
相关产品推荐
相关产品推荐

