美文网首页
django 自定义用户认证

django 自定义用户认证

作者: 撸大师 | 来源:发表于2017-05-02 17:44 被阅读1500次

前言:Django 自带的用户认证系统已经可以满足大部分的情况,但是有时候我们有某些特定的需求,比如把唯一标识改成email,或加入用户组等等,自定义用户认证可以根据项目的需求定制化和扩展认证系统。Django 的确是强大无比的,支持使用其他的认证系统、也可以扩展Django的User模块,还可以完全自定义新的认证模块。

官方文档: https://docs.djangoproject.com/en/1.11/topics/auth/customizing/

自定义用户 models

使用Django自定义用户模型必须满足:

模型必须有一个唯一的字段,可用于识别目的。
用户给定名称为“短”的标识,用户的全名为“长”标识符。他们可以返回完全相同的值。

构建一个符合用户自定义模型的最简单的方法是继承abstractbaseuser类。abstractbaseuser提供一个用户模型的核心实现,包括密码和符号密码重置。Django自带用用户认证User也是继承了它。一些关键的实现细节:

  • USERNAME_FIELD
    必须有一个唯一标识--USERNAME_FIELD
class MyUser(AbstractBaseUser):
    identifier = models.CharField(max_length=40, unique=True)
    ...
    USERNAME_FIELD = 'identifier'
  • REQUIRED_FIELDS
    创建superuser时的必须字段
class MyUser(AbstractBaseUser):
    ...
    date_of_birth = models.DateField()
    height = models.FloatField()
    ...
    REQUIRED_FIELDS = ['date_of_birth', 'height']

django 1.11 新增了EMAIL_FIELD,

  • abstractbaseuser提供的方法
    is_active(),is_authenticated()......

具体实现

# -*- coding: utf-8 -*-
# author: itimor
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
class CmsUserManager(BaseUserManager):
    def create_user(self, username, email, password=None):
        '''username 是唯一标识,没有会报错'''
        if not username:
            raise ValueError('Users must have an username')
        user = self.model(
            username=username,
            email=email,
        )
        user.set_password(password)  # 检测密码合理性
        user.save(using=self._db)  # 保存密码
        return user
    def create_superuser(self, username, email, password):
        user = self.create_user(username=username,
                                email=email,
                                password=password,
                                )
        user.is_admin = True  # 比创建用户多的一个字段
        user.save(using=self._db)
        return user
class CmsUser(AbstractBaseUser):
    username = models.CharField(max_length=32, unique=True, db_index=True)
    email = models.EmailField(max_length=255, unique=True, blank=True)
    name = models.CharField(max_length=100, verbose_name='中文名')
    head_img = models.ImageField(blank=True, upload_to="uploads/portrait", verbose_name='头像')
    group = models.ManyToManyField('CmsGroup', null=True, blank=True, verbose_name='部门或组')
    create_date = models.DateField(auto_now=True, verbose_name='创建时间')
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)
    USERNAME_FIELD = 'username'  # 必须有一个唯一标识--USERNAME_FIELD
    EMAIL_FIELD = 'email'
    REQUIRED_FIELDS = ['email']  # 创建superuser时的必须字段
    def get_full_name(self):
        return self.name
    def get_short_name(self):
        return self.username
    '''django自带后台权限控制,对哪些表有查看权限等'''
    def has_perm(self, perm, obj=None):
        return True
    '''用户是否有权限看到app'''
    def has_module_perms(self, app_label):
        return True
    def __str__(self):  # __unicode__ on Python 2
        return self.username
    @property
    def is_staff(self):
        return self.is_admin
    class Meta:
        verbose_name = '用户'
        verbose_name_plural = '用户'
        permissions = (
            ("view_users", "Can see available userlist"),
        )
    objects = CmsUserManager()  # 创建用户
class CmsGroup(models.Model):
    name = models.CharField(max_length=64, verbose_name='部门')
    owner = models.ForeignKey('CmsUser', default='admin', verbose_name='负责人')
    remarks = models.CharField(max_length=64, blank=True, verbose_name='备注')
    def __str__(self):
        return self.name
    class Meta:
        verbose_name = '组'
        verbose_name_plural = '部门'

修改全局设置

setting.py

AUTH_USER_MODEL = "users.CmsUser"

现在初始化数据库,登录后台。此时密码是明文显示,而且不能重置其他用户密码,这个时候我们还有自定义 admin显示

自定义用户 admin

# -*- coding: utf-8 -*-
# author: itimor
from django.contrib import admin
from users.models import CmsUser, CmsGroup
from django import forms
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
class UserCreationForm(forms.ModelForm):
    error_messages = {
        'password_mismatch': ("The two password fields didn't match."),
    }
    password1 = forms.CharField(label='密码', widget=forms.PasswordInput)
    password2 = forms.CharField(label='重复密码', widget=forms.PasswordInput)
    class Meta:
        model = CmsUser
        fields = ('username',)
    def clean_password2(self):
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError(
                self.error_messages['password_mismatch'],
                code='password_mismatch',
            )
        return password2
    def save(self, commit=True):
        user = super(UserCreationForm, self).save(commit=False)
        user.set_password(self.cleaned_data["password1"])
        if commit:
            user.save()
        return user
class UserChangeForm(forms.ModelForm):
    password = ReadOnlyPasswordHashField(label=("Password"),
                                         help_text=("你需要重新设置密码,不要犹豫了,老司机,<a href=\"../password/\">快上车</a>."))
    class Meta:
        model = CmsUser
        fields = '__all__'
    def clean_password(self):
        return self.initial["password"]
class GroupAdmin(admin.ModelAdmin):
    list_display = ('name', 'owner', 'remarks')
class UserAdmin(BaseUserAdmin):
    form = UserChangeForm
    add_form = UserCreationForm
    list_display = ('username', 'name', 'email', 'is_admin')
    list_filter = ('is_admin',)
    fieldsets = (
        ('Primary info', {'fields': ('username', 'password')}),
        ('Personal info', {'fields': ('email', 'name', 'group', 'head_img')}),
        ('Permissions', {'fields': ('is_admin', 'is_active')}),
    )
    add_fieldsets = (
        ('Add user', {
            'classes': ('wide',),
            'fields': ('username', 'email', 'name', 'password1', 'password2', 'group', 'is_admin', 'is_active')}
         ),
    )
    search_fields = ('username',)
    ordering = ('username',)
    filter_horizontal = ('group',)
admin.site.register(CmsUser, UserAdmin)
admin.site.register(CmsGroup, GroupAdmin)
admin.site.unregister(Group)

此时我们在登录后台查看。

效果查看

添加新用户

添加新用户

ps: 我给django admin换成 django-suit@v2,所以看这不一样,大家有兴趣也可以换成这个;

用户列表

用户列表

重置密码

点击 上车

重置密码

自此,自定义用户认证完成。

  • 遇到一个坑点
    重置密码那块,只要一点击就会404,
    password = ReadOnlyPasswordHashField(label=("Password"),
        help_text=("你需要重新设置密码,不要犹豫了,老司机,<a href=\"/password/\">快上车</a>."))

好多网上文档都一样,如果用上面的,点击重置时会跳到 id/change/password,找不到这个地址。
而 django 1.9+之后的 改成

    password = ReadOnlyPasswordHashField(label=("Password"),
        help_text=("你需要重新设置密码,不要犹豫了,老司机,<a href=\"../password/\">快上车</a>."))

链接是 id/password,这个才能正确的修改密码,找了好久终于在 stackoverflow 上面看到答案。

参考文档:http://www.cnblogs.com/daliangtou/p/5435385.html

相关文章

网友评论

      本文标题:django 自定义用户认证

      本文链接:https://www.haomeiwen.com/subject/kxqhtxtx.html