能否创建仅含单个字段的Django自定义用户模型?
没问题,我帮你一步步实现这个仅用token登录的Django自定义用户模型——完全不需要邮箱和密码,完美匹配你的需求:
首先在你的应用(比如命名为accounts)里的models.py中定义用户模型。我们需要继承AbstractBaseUser和PermissionsMixin(后者方便后续权限管理,不需要也可以只继承前者),并把你的token字段设为唯一认证标识:
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin from django.db import models class CustomUserManager(BaseUserManager): def create_user(self, auth_token): if not auth_token: raise ValueError("必须提供认证Token") user = self.model(auth_token=auth_token) # 因为不需要密码,直接保存即可 user.save(using=self._db) return user def create_superuser(self, auth_token): user = self.create_user(auth_token) user.is_staff = True user.is_superuser = True user.save(using=self._db) return user class CustomUser(AbstractBaseUser, PermissionsMixin): auth_token = models.CharField(max_length=255, unique=True, primary_key=True) is_active = models.BooleanField(default=True) is_staff = models.BooleanField(default=False) # 控制是否能登录admin后台 objects = CustomUserManager() # 指定用auth_token作为认证字段 USERNAME_FIELD = 'auth_token' REQUIRED_FIELDS = [] # 不需要其他必填字段 def __str__(self): return self.auth_token
这里把auth_token设为主键和唯一字段,USERNAME_FIELD告诉Django用这个字段做认证,REQUIRED_FIELDS留空因为不需要额外必填项。
在项目根目录的settings.py里指定自定义用户模型,替换掉默认的auth.User:
AUTH_USER_MODEL = 'accounts.CustomUser' # 注意替换成你的应用名和模型名
Django默认的认证逻辑是校验用户名+密码,我们需要写一个只校验auth_token的后端。在accounts应用下新建backends.py:
from django.contrib.auth.backends import BaseBackend from .models import CustomUser class TokenAuthBackend(BaseBackend): def authenticate(self, request, auth_token=None): try: # 查找匹配token的用户 user = CustomUser.objects.get(auth_token=auth_token) return user except CustomUser.DoesNotExist: # 没有匹配的用户返回None return None def get_user(self, user_id): try: return CustomUser.objects.get(pk=user_id) except CustomUser.DoesNotExist: return None
然后回到settings.py,配置使用这个认证后端:
AUTHENTICATION_BACKENDS = [ 'accounts.backends.TokenAuthBackend', # 如果需要保留默认的admin密码登录(比如超级用户),可以加上下面这行: # 'django.contrib.auth.backends.ModelBackend', ]
如果是用传统的表单登录,默认的LoginView需要用户名和密码,所以我们要自己写登录视图和表单。在accounts/views.py里:
from django.contrib.auth import login, authenticate from django.shortcuts import render, redirect from django import forms class TokenLoginForm(forms.Form): auth_token = forms.CharField(label='认证Token', max_length=255) def token_login(request): if request.method == 'POST': form = TokenLoginForm(request.POST) if form.is_valid(): auth_token = form.cleaned_data['auth_token'] # 用我们自定义的后端验证token user = authenticate(request, auth_token=auth_token) if user is not None: login(request, user) return redirect('home') # 登录成功跳转到你的主页 else: form.add_error('auth_token', '无效的认证Token') else: form = TokenLoginForm() return render(request, 'accounts/token_login.html', {'form': form})
然后创建对应的模板templates/accounts/token_login.html:
<form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">登录</button> </form>
最后在accounts/urls.py里添加登录路由:
from django.urls import path from .views import token_login urlpatterns = [ path('login/', token_login, name='token_login'), ]
完成以上步骤后,运行迁移命令创建用户表:
python manage.py makemigrations python manage.py migrate
默认的Admin后台会显示密码字段,我们需要自定义UserAdmin来适配我们的用户模型。在accounts/admin.py里:
from django.contrib import admin from django.contrib.auth.admin import UserAdmin from .models import CustomUser class CustomUserAdmin(UserAdmin): list_display = ('auth_token', 'is_staff', 'is_active') fieldsets = ( (None, {'fields': ('auth_token',)}), ('权限设置', {'fields': ('is_staff', 'is_active', 'is_superuser')}), ) add_fieldsets = ( (None, { 'classes': ('wide',), 'fields': ('auth_token', 'is_staff', 'is_active'), }), ) search_fields = ('auth_token',) ordering = ('auth_token',) admin.site.register(CustomUser, CustomUserAdmin)
这样Admin后台就只会显示auth_token和权限相关的字段,没有多余的密码输入框了。
内容的提问来源于stack exchange,提问作者user5721897

