django 自定義用戶認證

前言:Django 自帶的用戶認證系統(tǒng)已經(jīng)可以滿足大部分的情況,但是有時候我們有某些特定的需求,比如把唯一標識改成email,或加入用戶組等等挪挤,自定義用戶認證可以根據(jù)項目的需求定制化和擴展認證系統(tǒng)。Django 的確是強大無比的关翎,支持使用其他的認證系統(tǒng)扛门、也可以擴展Django的User模塊,還可以完全自定義新的認證模塊纵寝。

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

自定義用戶 models

使用Django自定義用戶模型必須滿足:

模型必須有一個唯一的字段论寨,可用于識別目的。
用戶給定名稱為“短”的標識爽茴,用戶的全名為“長”標識符葬凳。他們可以返回完全相同的值。

構(gòu)建一個符合用戶自定義模型的最簡單的方法是繼承abstractbaseuser類室奏。abstractbaseuser提供一個用戶模型的核心實現(xiàn)火焰,包括密碼和符號密碼重置。Django自帶用用戶認證User也是繼承了它胧沫。一些關(guān)鍵的實現(xiàn)細節(jié):

  • USERNAME_FIELD
    必須有一個唯一標識--USERNAME_FIELD
class MyUser(AbstractBaseUser):
    identifier = models.CharField(max_length=40, unique=True)
    ...
    USERNAME_FIELD = 'identifier'
  • REQUIRED_FIELDS
    創(chuàng)建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()......

具體實現(xiàn)

# -*- 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  # 比創(chuàng)建用戶多的一個字段
        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='創(chuàng)建時間')
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)
    USERNAME_FIELD = 'username'  # 必須有一個唯一標識--USERNAME_FIELD
    EMAIL_FIELD = 'email'
    REQUIRED_FIELDS = ['email']  # 創(chuàng)建superuser時的必須字段
    def get_full_name(self):
        return self.name
    def get_short_name(self):
        return self.username
    '''django自帶后臺權(quán)限控制占业,對哪些表有查看權(quán)限等'''
    def has_perm(self, perm, obj=None):
        return True
    '''用戶是否有權(quán)限看到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()  # 創(chuàng)建用戶
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"

現(xiàn)在初始化數(shù)據(jù)庫,登錄后臺纯赎。此時密碼是明文顯示谦疾,而且不能重置其他用戶密碼,這個時候我們還有自定義 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>."))

好多網(wǎng)上文檔都一樣,如果用上面的必搞,點擊重置時會跳到 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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末泌类,一起剝皮案震驚了整個濱河市癞谒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌刃榨,老刑警劉巖弹砚,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異枢希,居然都是意外死亡桌吃,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門苞轿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來茅诱,“玉大人逗物,你說我怎么就攤上這事∪貌荆” “怎么了敬察?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長尔当。 經(jīng)常有香客問我莲祸,道長,這世上最難降的妖魔是什么椭迎? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任锐帜,我火速辦了婚禮,結(jié)果婚禮上畜号,老公的妹妹穿的比我還像新娘缴阎。我一直安慰自己,他們只是感情好简软,可當我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布蛮拔。 她就那樣靜靜地躺著,像睡著了一般痹升。 火紅的嫁衣襯著肌膚如雪建炫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天疼蛾,我揣著相機與錄音肛跌,去河邊找鬼。 笑死察郁,一個胖子當著我的面吹牛衍慎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播皮钠,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼稳捆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了鳞芙?” 一聲冷哼從身側(cè)響起眷柔,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎原朝,沒想到半個月后驯嘱,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡喳坠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年鞠评,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片壕鹉。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡剃幌,死狀恐怖聋涨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情负乡,我是刑警寧澤牍白,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站抖棘,受9級特大地震影響茂腥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜切省,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一最岗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧朝捆,春花似錦般渡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至儒老,卻和暖如春晨汹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贷盲。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留剥扣,地道東北人巩剖。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像钠怯,于是被迫代替她去往敵國和親佳魔。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 官方文檔:https://docs.djangoproject.com/en/1.10/topics/auth/c...
    SateZheng閱讀 2,155評論 1 4
  • cms_project 項目晦炊,自定義用戶和相關(guān)權(quán)限設置 1.重寫用戶模型 1.1 修改配置文件鞠鲜,覆蓋默認的User...
    常大鵬閱讀 25,863評論 1 26
  • django——重寫用戶模型 Django內(nèi)建的User模型可能不適合某些類型的項目。例如断国,在某些網(wǎng)站上使用郵件地...
    常大鵬閱讀 26,320評論 2 29
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理贤姆,服務發(fā)現(xiàn),斷路器稳衬,智...
    卡卡羅2017閱讀 134,696評論 18 139
  • 4 創(chuàng)建一個社交網(wǎng)站 在上一章中霞捡,你學習了如何創(chuàng)建站點地圖和訂閱,并且為博客應用構(gòu)建了一個搜索引擎薄疚。在這一章中碧信,你...
    lakerszhy閱讀 2,190評論 0 7