Django自帶的用戶認證auth模塊

1、介紹

基本上在任何網站上,都無可避免的須要設計實現網站的用戶系統。此時咱們須要實現包括用戶註冊、用戶登陸、用戶認證、註銷、修改密碼等功能。

使用Django,咱們能夠不須要本身寫這些功能,由於Django內置了強大的用戶認證系統--auth,它默認使用 auth_user 表來存儲用戶數據。

from django.contrib import auth  # 使用auth認證系統
from django.contrib.auth.models import User # auth認證系統默認使用User表 注意:命令行建立超級用戶 python manage.py createsuperuser

 

2、authenticate() 

提供了用戶認證功能,即驗證用戶名以及密碼是否正確,通常須要username 、password兩個關鍵字參數。
若是認證成功(用戶名和密碼正確有效),便會返回一個 User 對象。

authenticate()會在該 User 對象上設置一個屬性(id)來標識後端已經認證了該用戶,且該信息在後續的登陸過程當中是須要的。

用法:
from django.contrib import auth user_obj
= auth.authenticate(username=username,password=pwd)

 

3、login(request, user)

該函數接受一個HttpRequest對象,以及一個通過認證的User對象。
該函數實現一個用戶登陸的功能。它本質上會在後端爲該用戶生成相關session數據。

用法:auth.login(request, user_obj)

示例:
from django.shortcuts import render, HttpResponse, redirect
from django.contrib import auth

def login(request):
    if request.method == "POST":
        username = request.POST.get('username')
        pwd = request.POST.get('password')
        # 調用auth模塊的認證方法,判斷用戶名和密碼是否正確,正確返回一個user_obj
        user_obj = auth.authenticate(username=username, password=pwd)
        if user_obj:
            # 登陸成功,設置Session數據
            auth.login(request, user_obj)
            return HttpResponse('登陸成功')
        else:
            return render(request, 'login.html', {'error_msg': '用戶名或者密碼錯誤'})
    return render(request, 'login.html')

注意:
只要使用login(request, user_obj)以後,request.user就能拿到當前登陸的用戶對象。不然request.user獲得的是一個匿名用戶對象(AnonymousUser Object)。
詳細原理請查看 AuthenticationMiddleware 中間件源碼。

 

4、logout(request) 

該函數接受一個HttpRequest對象,無返回值。
當調用該函數時,當前請求的session信息會所有清除。該用戶即便沒有登陸,使用該函數也不會報錯。

用法:

from django.contrib import auth
   
def logout(request):
    auth.logout(request)
    return redirect('/login/')

 

5、login_requierd()

auth 給咱們提供的一個裝飾器工具,用來快捷的給某個視圖添加登陸校驗。

用法:
from django.contrib.auth.decorators import login_required
      
@login_required
def index(request):
    return render(request, 'index.html')

若用戶沒有登陸,則會跳轉到django默認的登陸URL '/accounts/login/ ' 並傳遞當前訪問url的絕對路徑 (登錄成功後,會重定向到該路徑)。
若是須要自定義登陸的URL,則須要在settings.py文件中經過LOGIN_URL進行修改。

示例:
LOGIN_URL = '/login/'  # 這裏配置成你項目登陸頁面的路由

 

6、create_user()

auth 提供的一個建立新用戶的方法,須要提供必要參數(username、password)等。

用法:
from django.contrib.auth.models import User
user = User.objects.create_user(username='用戶名',password='密碼',email='郵箱',...)


示例:
def reg(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        pwd = request.POST.get('password')
        # 假設數據都通過有效性校驗了
        # 去數據庫建立一條記錄
        User.objects.create_user(username=username, password=pwd)  # create_user建立普通用戶
        # User.objects.create_superuser(username=username, password=pwd)  # create_superuser建立超級用戶
        # 建立成功,跳轉登陸頁年
        return redirect('/login/')

    return render(request, 'reg.html')

 

7、create_superuser()

auth 提供的一個建立新的超級用戶的方法,須要提供必要參數(username、password)等。

用法:
from django.contrib.auth.models import User
user_obj = User.objects.create_superuser(username='用戶名',password='密碼',email='郵箱',...)

 

8、check_password(raw_password)

auth 提供的一個檢查密碼是否正確的方法,須要提供當前請求用戶的密碼。
密碼正確返回True,不然返回False。

用法:
ok = user_obj.check_password('密碼')
或者直接針對當前請求的user對象校驗原密碼是否正確:
ok = request.user.check_password(raw_password='原密碼')

 

9、set_password(raw_password)

auth 提供的一個修改密碼的方法,接收要設置的新密碼 做爲參數。
注意:設置完必定要調用用戶對象的save方法!!!

用法:
user_obj.set_password('新密碼')
user_obj.save()

 

10、is_authenticated()

用來判斷當前請求是否經過了認證。

用法:

def my_view(request):
  if not request.user.is_authenticated():
    return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))

 

11、用戶對象的屬性

從user_obj = request.user能夠拿到當前登陸的用戶對象,用戶對象user_obj可以拿到認證所用用戶表的數據屬性,好比username, password等。

其餘經常使用屬性含義以下:
is_staff : 用戶是否擁有網站的管理權限.

is_active : 是否容許用戶登陸, 設置爲 False,能夠在不刪除用戶的前提下禁止用戶登陸。

 

12、如何拓展auth默認的表

1、介紹
雖然內置的認證系統很好用,可是auth_user表字段都是固定的那幾個,若是我想要加一個存儲用戶手機號的字段怎麼辦?
方法一:新建另一張表而後經過一對一和內置的auth_user表關聯
方法二:經過繼承內置的AbstractUser類,來定義一個本身的Model類。
這樣既能根據項目需求靈活的設計用戶表,又能使用Django強大的認證系統了。

2、示例:
models.py
from django.db import models
from django.contrib.auth.models import AbstractUser


class UserInfo(AbstractUser):
    # 這裏定義拓展的字段
    gender = models.PositiveIntegerField(choices=((0, ''),(1, ''), (2, '保密')))
    phone = models.CharField(max_length=11)

3、注意:
按上面的方式擴展了內置的auth_user表以後,必定要在settings.py中告訴Django,我如今使用我新定義的UserInfo表來作用戶認證。寫法以下:
# 引用Django自帶的User表,繼承使用時須要設置
AUTH_USER_MODEL = "app名.UserInfo"


4、自定義認證系統默認使用的數據表以後,咱們就能夠像使用默認的auth_user表那樣使用咱們的UserInfo表了。好比:

建立普通用戶:
UserInfo.objects.create_user(username='用戶名', password='密碼')

建立超級用戶:
UserInfo.objects.create_superuser(username='用戶名', password='密碼')


5、再次注意:
一旦咱們指定了新的認證系統所使用的表,咱們就須要從新在數據庫中建立該表,而不能繼續使用原來默認的auth_user表了。
默認的auth_user表就會被你自定義的表替代,即auth_user表不存在了,咱們使用auth模塊的方法,修改的就是新的表。
繼承AbstractUser是在User表的基礎上拓展字段,User表原來的字段仍是有的,可是若是我就不想要User表的某些字段,並且還要拓展我須要的字段呢?
怎麼辦?就須要繼承AbstractBaseUser, PermissionsMixin重寫一個表,表內的字段徹底是你設計的字段
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager

# 定義UserProfile這個類的管理類
class UserManager(BaseUserManager):
    use_in_migrations = True

    def _create_user(self, email, password, **extra_fields):
        """
        Creates and saves a User with the given email and password.
        """
        if not email:
            raise ValueError('The given email must be set')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)  # 建立對象
        user.set_password(password)  # 把密碼加密以後再寫入數據庫
        user.save(using=self._db)  # 保存到數據庫
        return user

    def create_user(self, email, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', False)  # 給字典設置默認值
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(email, password, **extra_fields)

    def create_superuser(self, email, password, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')
        return self._create_user(email, password, **extra_fields)


class UserProfile(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(
        max_length=255,
        unique=True,
        validators=[RegexValidator(r'^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$', '郵箱格式不正確'),]
    )
    is_staff = models.BooleanField(
        _('staff status'),
        default=False,
        help_text=_('Designates whether the user can log into this admin site.'),
    )
    is_active = models.BooleanField(
        _('active'),
        default=True,
        help_text=_(
            'Designates whether this user should be treated as active. '
            'Unselect this instead of deleting accounts.'
        ),
    )
    name = models.CharField('名字', max_length=32)
    department = models.ForeignKey('Department', default=None, blank=True, null=True)
    mobile = models.CharField(
        '手機',
        max_length=32,
        default=None,
        blank=True,
        null=True,
        validators=[RegexValidator(r'^1[3-9]\d{9}$', '手機格式不正確')]
    )

    memo = models.TextField('備註', blank=True, null=True, default=None)
    date_joined = models.DateTimeField(auto_now_add=True)

    EMAIL_FIELD = 'email'  # 發送郵件的字段
    USERNAME_FIELD = 'email'  # 用來惟一肯定auth中的用戶
    REQUIRED_FIELDS = ['name']  # auth指定除了上面兩個配置項的字段還有哪些字段須要必填

    class Meta:
        verbose_name = '帳戶信息'
        verbose_name_plural = "帳戶信息"

    def clean(self):
        super(UserProfile, self).clean()
        # 對郵件進行校驗
        self.email = self.__class__.objects.normalize_email(self.email)

    def get_full_name(self):
        # The user is identified by their email address
        return self.name

    def get_short_name(self):
        # The user is identified by their email address
        return self.email

    def __str__(self):  # __unicode__ on Python 2
        return self.name

    # 給ORM添加管理類
    objects = UserManager()
View Code
 

 

十3、修改密碼示例

@login_required
def set_password(request):
    user = request.user
    err_msg = ''
    if request.method == 'POST':
        old_password = request.POST.get('old_password')
        new_password = request.POST.get('new_password')
        re_password = request.POST.get('re_password')
        # 檢查舊密碼是否正確
        if user.check_password(old_password):
            if not new_password:
                err_msg = '新密碼不能爲空'
            elif new_password != re_password:
                err_msg = '兩次密碼不一致'
            else:
                user.set_password(new_password)
                user.save()
                return redirect("/login/")
        else:
            err_msg = '原密碼輸入錯誤'
    return render(request, 'set_password.html', {'err_msg': err_msg})
View Code
相關文章
相關標籤/搜索