1. 程式人生 > >Django的使用者模組與許可權系統

Django的使用者模組與許可權系統

一 導言

設計一個好的使用者系統往往不是那麼容易,Django提供的使用者系統可以快速實現基本的功能,並可以在此基礎上繼續擴充套件以滿足我們的需求。

先看看Django的使用者系統都提供哪些功能:

  • 提供使用者模組(User Model)
  • 許可權驗證(預設新增已有模組的增加刪除修改許可權)
  • 使用者組與組許可權功能
  • 使用者鑑權與登入功能
  • 與使用者登入驗證相關的一些函式與裝飾方法

如配置了Django的使用者系統,僅需呼叫Django提供的幾個函式,便可實現使用者的登入,登出,許可權驗證等功能。例如以下情景

1.登入

# some_view.py
from django.contrib.auth
import authenticate, login def login(request): username = request.POST['username'] password = request.POST['password'] # Django提供的authenticate函式,驗證使用者名稱和密碼是否在資料庫中匹配 user = authenticate(username=username, password=password) if user is not None: # Django提供的login函式,將當前登入使用者資訊儲存到會話key中
login(request, user) # 進行登入成功的操作,重定向到某處等 ... else: # 返回使用者名稱和密碼錯誤資訊 ...

2.登出

# some_view.py
from django.contrib.auth import logout

def logout(request):
    # logout函式會清除當前使用者儲存在會話中的資訊
    logout(request)

3.驗證是否登入

# some_view.py

def some_fuction
(request): user = request.user if user.is_authenticated: # 已登入使用者,可以往下進行操作 else: # 返回要求登入資訊

4.驗證是否有許可權

# some_view.py

def some_fuction(request):
    user = request.user
    if user.has_perm('myapp.change_bar'):
        # 有許可權,可以往下進行操作
    else:
        # 返回禁止訪問等資訊

二 使用者模組

Django的使用者模組類定義在auth應用中,如要直接使用Django的使用者類,在setting配置檔案中的INSTALLAPP新增一行django.contrib.auth

這樣就可以在程式碼中直接用User類建立使用者:

from django.contrib.auth.models import User
user = User.objects.create_user('john', '[email protected]', 'johnpassword')
user.last_name = 'Lennon'
user.save()

看看Django的原始碼User類定義了什麼屬性:

class User(AbstractUser):
    """
    Users within the Django authentication system are represented by this
    model.
    Username, password and email are required. Other fields are optional.
    """
    class Meta(AbstractUser.Meta):
        swappable = 'AUTH_USER_MODEL'

…,啥都沒有?

注意到User類繼承AbstractUser類, 使用者名稱和密碼資訊等定義在父類了。所以再看看AbstractUser類的定義, 限於篇幅僅列出其中一部分,原始碼在https://github.com/django/django/blob/master/django/contrib/auth/models.py

class AbstractUser(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(
        _('username'),
        max_length=150,
        unique=True,
        help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
        validators=[username_validator],
        error_messages={
            'unique': _("A user with that username already exists."),
        },
    )
    first_name = models.CharField(_('first name'), max_length=30, blank=True)
    last_name = models.CharField(_('last name'), max_length=30, blank=True)
    email = models.EmailField(_('email address'), blank=True)
    date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
....

可以看到AbstractUser類中定義了username這個欄位了,另外還有email、first_name、last_name等。AbstractUser類還繼承AbstractBaseUser和PermissionsMixin類,AbstractBaseUser類提供password欄位及將密碼加密儲存的相關方法,PermissionsMixin類提供User類許可權認證功能。

總的來說,一個User類,定義了以下欄位:

  • username: 使用者名稱
  • password: 密碼
  • first_name: 姓名
  • last_name: 姓名
  • email: 郵箱
  • groups: Group類多對多的關係物件管理器
  • user_permissions: Permission類多對多的關係物件管理器
  • is_staff: 是否工作人員
  • is_active: 是否啟用
  • is_superuser: 是否管理員
  • last_login: 最近登入時間
  • date_joined: 註冊時間

另外,生成一個User例項,可以使用以下屬性:

  • is_authenticated: 只讀,用來判斷使用者是否存在。只有AnonymousUser類這個屬性為False。
  • is_anonymous: 就是用來區分 User 和 AnonymousUser 物件而已。

User類提供了許多方法方便我們執行各種操作:

  • set_password(raw_password): 可以將password轉成hash值,記得再呼叫user.save()儲存。
  • check_password(raw_password): 相反,將原生密碼與儲存在資料庫中hash值密碼對比(直接對比肯定不相同的)。
  • has_perm(perm, obj=None),has_perms(perm_list, obj=None): 驗證該使用者是否擁有某個許可權或者許可權列表
  • get_all_permissions(obj=None): 返回該使用者擁有的所有許可權

三 驗證與登入使用者

驗證使用者名稱和密碼看起來很簡單,對比提交的使用者名稱和密碼與資料庫儲存的一致即可。

如:

# some_view.py
def some_fuction(request):
    username = request.POST['username']
    password = request.POST['password']
    try:
        user = User.objects.get(username=username, password=password)
    except ObjectNotExists:
        # 使用者名稱和密碼不匹配一個使用者

    ...

由於密碼已經進行hash後儲存,上述程式碼還得先把提交的password值先hash再去資料庫中搜索,總得多寫了一些程式碼。這些Django都已經考慮到了, 提供了一個authenticate函式驗證是否存在該使用者,就像導言的例項程式碼:

# some_view.py
from django.contrib.auth import authenticate, login

def login(request):
    username = request.POST['username']
    password = request.POST['password']
    user = authenticate(username=username, password=password)
    if user is not None:
        login(request, user)
        ...
    else:
        ...

這裡重點說明一下authenticate和login函式。

1.authenticate(**credentials)

傳入待驗證的引數,預設是username和password,它會呼叫系統配置裡的每一個authentication backend進行驗證,驗證通過返回一個User例項,否則返回None。

每一個authentication backend指認證後端,在setting.py中配置的AUTHENTICATION_BACKENDS變數,預設是[‘django.contrib.auth.backends.ModelBackend’],可以增加自定義的認證後端,或者使用第三方提供的。authenticate函式會按順序呼叫每一個進行驗證,如果第一個沒有通過,它會使用第二個進行驗證,直到所有的認證後端都失敗後才返回None。

看看這個ModelBackend類如何返回認證使用者(再次縮減原始碼):

class ModelBackend(object):
    def authenticate(self, request, username=None, password=None, **kwargs):
        if username is None:
            username = kwargs.get(UserModel.USERNAME_FIELD)
        try:
            user = UserModel._default_manager.get_by_natural_key(username)
        except UserModel.DoesNotExist:

            UserModel().set_password(password)
        else:
            if user.check_password(password) and self.user_can_authenticate(user):
                return user
# ...

實際上authenticate函式會呼叫每一個authentication backend類的authenticate方法, ModelBackend類與我們之前的驗證方法稍有不同,它先從資料庫使用者表中取出與username對應的一個User例項,再通過User的check_password方法驗證password是否正確,並返回這個User例項。

2.login(request, user, backend=None)

接收HttpRequest物件和一個User物件,login函式會將當前使用者資訊儲存到會話cookie中,所以要使用Django使用者系統的所有功能,也得安裝Django預設的會話APP。

看看login函式做了什麼:

def login(request, user, backend=None):
    # (清空當前的session資訊)
    # ...
    request.session[SESSION_KEY] = user._meta.pk.value_to_string(user)
    request.session[BACKEND_SESSION_KEY] = backend
    request.session[HASH_SESSION_KEY] = session_auth_hash
    if hasattr(request, 'user'):
       request.user = user
    rotate_token(request)
    user_logged_in.send(sender=user.__class__, request=request, user=user)

login函式將當前使用者的一個唯一標識資訊儲存在request.session的SESSION_KEY中, 下次請求時即可從會話cookie中拿到當前登入的使用者物件。

如果要求登入使用者才能訪問相應的View,可以這麼寫:

from django.conf import settings
from django.shortcuts import redirect

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

通過login函式可以將使用者資訊儲存在會話中,當下一個請求到達view前,Django的會話中介軟體從會話cookie中取出使用者物件,並賦值給request.user。這樣,已登入的使用者request.user.is_authenticated值為True,可以進行相應的操作。未登入使用者request.user返回一個AnonymousUser物件,它的is_authenticated屬性值永遠為False,那麼要將這個請求重定向到登入頁面。

這兩行程式碼可以通過在view函式上加一個裝飾器實現,如

@login_required
def my_view(request):
    ...

裝飾器login_required(redirect_field_name='next', login_url=None), 可傳入login_url引數設定未登入使用者的請求重定向的地址,否則重定向到settings.LOGIN_URL。

四 許可權認證

User模型有兩個多對多關係的欄位: groups 和 user_permissions, 它們與Pemission模型有關。User與Pemission、User與Permission、Group與Permission均是多對多關係, Permission定義了具體的許可權,其欄位如下:

class Permission(models.Model):
    name = models.CharField(_('name'), max_length=255)      # 許可權名稱(用作顯示)
    content_type = models.ForeignKey(       # 內容型別: 每個模型對應一個內容型別,用於定位指定模型
        ContentType,
        models.CASCADE,
        verbose_name=_('content type'),
    )
    codename = models.CharField(_('codename'), max_length=100)   # 許可權的程式碼名稱,用在如has_permission函式引數

給一個使用者新增、刪除許可權很簡單: myuser.user_permissions.set([permission_list]) myuser.user_permissions.add(permission, permission, …) myuser.user_permissions.remove(permission, permission, …) myuser.user_permissions.clear()

其中,permission是具體的permission物件。 也可以通過使用者所在的組新增相應的許可權: group.permissions.set([permission_list]) group.permissions.add(permission, permission, …) group.permissions.remove(permission, permission, …) group.permissions.clear()

只要這個使用者加入該組也擁有組許可權。通過User物件的get_all_permissions(obj=None)方法可以獲得該使用者的所有許可權列表(字元列表),也可以通過get_group_permissions(obj=None)獲得對應的組許可權列表。

我們更經常要做的是在view中執行操作之前驗證使用者是否擁有指定許可權,這裡一般用到User物件的has_perm(perm, obj=None)方法或者has_perms(perm_list, obj=None)判斷。

has_perm(perm, obj=None)方法中perm是”."格式的許可權字串, 如果有這個許可權,方法會返回True。同樣,`has_perms(perm_list, obj=None)`方法中perm_list中是"."格式的許可權字串列表。

同login_required裝飾器,許可權認證也有對應的permission_required裝飾器:

permission_required(perm, login_url=None, raise_exception=False)

如果raise_exception=True, 許可權沒有認證通過則丟擲PermissionDenied異常,返回預設的403頁面。

Done.

原文地址:http://neven.me/django/2016/11/26/Django%E7%9A%84%E7%94%A8%E6%88%B7%E6%A8%A1%E5%9D%97%E4%B8%8E%E6%9D%83%E9%99%90%E7%B3%BB%E7%BB%9F/

相關推薦

Django-使用者模組許可權系統相關

Django的使用者模組與許可權系統 Django的使用者系統都提供哪些功能: 提供使用者模組(User Model) 許可權驗證(預設新增已有模組的增加刪除修改許可權) 使用者組與組許可權功能 使用者鑑權與登入功能 與使用者登入驗證相關的一些函式與裝飾方法   1

Django的使用者模組許可權系統

一 導言 設計一個好的使用者系統往往不是那麼容易,Django提供的使用者系統可以快速實現基本的功能,並可以在此基礎上繼續擴充套件以滿足我們的需求。 先看看Django的使用者系統都提供哪些功能: 提供使用者模組(User Model)許可權驗證(預設新增已有模組的增

Django原始碼分析之許可權系統_擒賊先擒王

乍見 Django內建的許可權系統已經很完善了,加上django-guardian提供的功能,基本上能滿足大部分的許可權需求。暫且不說django-guardian,我們先來看下Django內建的許可權系統:django.contrib.auth 包。 相識 一般許可權系統分為全域性許可權和物件許可權。

Django使用者登入註冊系統

一、建立專案 1.1.建立專案和app django-admin startproject mysite_login python manage.py startapp login 1.2.設定時區和語言 Django預設使用美國時間和英語,在專案的settings檔案中,如下所示:

SpringSecurity原理剖析許可權系統設計

Spring Secutity和Apache Shiro是Java領域的兩大主流開源安全框架,也是許可權系統設計的主要技術選型。本文主要介紹Spring Secutity的實現原理,並基於Spring Secutity設計基於RBAC的許可權系統。 一、技術選型 為何把Spring Secutity作為許可權

django許可權系統auth模組概述

Django許可權系統auth模組概述 轉自:原文出處 auth模組是Django提供的標準許可權管理系統,可以提供使用者身份認證, 使用者組和

Django許可權系統身份驗證模組詳解

轉自:原文出處身份驗證模組是Django中提供的標準許可權管理系統,提供可以使用者身份認證,使用者組和許可權管理。AUTH可以和管理模組配合使用,快速建立網站的管理系統。在INSTALLED_APPS中新增 'django.contrib.auth' 使用該應用程式,身份驗證模組預設啟用。使用者使用者是AUT

Django中Admin管理許可權管理(三)————模組的鑑權操作

通知模組的鑑權操作1.定義許可權這裡需要給大家提的是,在我們新建模型完成之後,系統會自動的給這個模型定義三個許可權。我們可以通過認證和授權中的組來進行檢視。如下圖所示,我們可以看到預設新增的三個許可權資訊。當然啦,在實際執行環境中,我們難免要對許可權進行擴充套件。所以我們就

asp.net後臺管理系統-登陸模組-路由許可權控制_1

using System.Web.Routing; //重寫System.Web.Routing中Initialize方法 protected override void Initialize(RequestContext requestContext) {

系統之登陸判斷許可權

1.配置攔截器 <mvc:interceptors> <bean class="com.dy.admin.interceptor.AdminLoginHandlerInterceptor"/> </mvc:interceptors>

Django如何建立一套介面級別的許可權系統

從零開始搭建當然是可以的,但是Django的特色就是大而全,所以,我的方案是,利用現有的Django框架,實現功能。 我用的pycharm,操作很方便快捷。 | auth_group | | auth_group_permissi

mysql 開發進階篇系列 52 許可權安全(系統四個許可權表的粒度控制關係)

一.概述   接著上篇的許可權介紹,當用戶進行連線的時候,許可權表的存取過程有以下兩個階段:   (1) 先從user表中的host,user, authentication_string 這3個欄位中判斷連線的ip,使用者名稱,密碼是否存在於表中,如果存在,則通過身份驗證。   (2) 通過驗證後,則按照以

許可權系統RBAC模型概述[絕對經典]

0. 前言 一年前,我負責的一個專案中需要許可權管理。當時憑著自己的邏輯設計出了一套許可權管理模型,基本原理與RBAC非常相似,只是過於簡陋。當時google了一些許可權管理的資料,從中瞭解到早就有了RBAC這個東西。可惜一直沒狠下心來學習。 更詳細的

許可權系統RBAC模型概述

RBAC(Role-Based Access Control,基於角色的訪問控制),就是使用者通過角色與許可權進行關聯。簡單地說,一個使用者擁有若干角色,每一個角色擁有若干許可權。這樣,就構造成“使用者-角色-許可權”的授權模型。在這種模型中,使用者與角色之間,角色與許可權之間,一般者是多對多的關係。(如下圖

【ITOO高校雲平臺】——淺析許可權系統中角色職位

【前言】在ITOO高校雲平臺中,許可權管理,由於涉及到基礎系統的資料,所以存在角色和職位這兩個概念。針對兩者的關係和區別,也一直是我們探討的熱點。 今天,在這裡我們重新梳理一下。 一、角色 角色

Android4.4系統瀏覽器Chromium實現的載入模組流程

 本文只描述Http網路請求相關的資訊,Https、Spdy、file、ftp、websocket等的型別只提及在哪裡出現關係分支。 PS:一部分實現是在content層的,所以這裡其實並不全,例如沒提到URLRequestContext、CookieStore。

Oracle許可權-系統許可權物件許可權

系統許可權與物件許可權一、系統許可權 1、建立使用者 SQL> create user dog identified by wangwang; User created SQL> create user pig identified by hengheng; U

許可權系統--角色授權許可權變更

許可權系統中一般都是為角色授權,然後屬於該角色的的使用者都會擁有該角色的許可權。 一:介面展示 點選角色授權按鈕後會彈出當前角色已經授權的許可權樹(含checkbox),使用者通過選中對應的許可權

Android程式執行時許可權檔案系統許可權,普通許可權及危險許可權的區別

面試時遇到這樣的題目   問題來的太突然,完全沒有準備,結果我想到了android 6.0之後推出的 normal permissions 和 dangerous permissions 並且把這兩者之間的關係答了一下,而且還舉了個例子,現在想想,真是丟人 關於普通

基於Spring Boot AOP使用者許可權系統模組開發

    公司專案需要涉及到使用者許可權的問題,每個使用者都應該有自己的許可權,而且許可權應該是靈活可變的,系統的登陸模組因為涉及到分散式部署的問題以及前後端分離,不能採用傳統的session作為登陸方式,而是採用JWT的方式實現,保證了介面的無狀態性,但是這樣的話也就讓市面上