1. 程式人生 > >在Django中定制身份驗證

在Django中定制身份驗證

save hang 一個用戶 因此 myba 重新 delete targe exc

在Django中定制身份驗證

Django附帶的認證對於大多數常見情況來說已經足夠了,但您可能需要通過開箱即用的默認設置才能滿足需求。 要為您的項目定制身份驗證,需要了解提供的系統的哪些點可擴展或可替換。

身份驗證後端為用戶模型存儲的用戶名和密碼需要針對與Django默認不同的服務進行身份驗證時提供了一個可擴展的系統。 您可以給您的模型定制可以通過Django的授權系統進行檢查的權限。 您可以擴展默認的用戶模型,或者替換完全自定義的模型。

其他驗證來源

您可能有時需要掛接到另一個身份驗證來源 - 也就是另一個用戶名和密碼來源或身份驗證方法。

例如,您的公司可能已經有一個LDAP設置,為每個員工存儲用戶名和密碼。如果用戶在LDAP和基於Django的應用程序中有單獨的帳戶,那麽對網絡管理員和用戶本身來說都是一件麻煩事。

所以,為了處理這樣的情況,Django認證系統可以讓你插入其他認證源。您可以重寫Django的默認基於數據庫的方案,或者可以與其他系統一起使用默認系統。

指定認證後端

在幕後,Django維護一個驗證後端列表,它檢查身份驗證。當有人調用authenticate()時(正如前一節中介紹的有關登錄用戶的內容),Django會嘗試在其所有身份驗證後端進行身份驗證。如果第一種認證方法失敗,
Django嘗試第二個,等等,直到所有的後端嘗試。

在AUTHENTICATION_BACKENDS設置中指定要使用的身份驗證後端列表。 這應該是一個Python路徑名列表,指向知道如何進行身份驗證的Python類。 這些類可以在你的Python路徑上的任何地方。 默認情況下,AUTHENTICATION_BACKENDS
被設定為:

[‘django.contrib.auth.backends.ModelBackend‘]

這是檢查Django用戶數據庫並查詢內置權限的基本身份驗證後端。它不提供通過任何速率限制機制防止暴力攻擊的保護。您可以在自定義授權後端中實現您自己的速率限制機制,也可以使用大多數Web服務器提供的機制。 AUTHENTICATION_BACKENDS的順序很重要,所以如果相同的用戶名和密碼在多個後端有效,Django將在第一次正面匹配時停止處理。如果後端引發PermissionDenied異常,認證將立即失敗。 Django不會檢查後面的後端。

一旦用戶通過身份驗證,Django就會存儲哪些後端用於在用戶會話中對用戶進行身份驗證,並在需要訪問當前身份驗證的用戶時在該會話期間重新使用相同的後端。這實際上意味著每個會話都會緩存身份驗證源,因此如果您更改AUTHENTICATION_BACKENDS,則需要清除會話數據(如果需要強制用戶使用不同方法重新進行身份驗證)。一個簡單的方法就是執行Session.objects.all().delete()

編寫身份驗證後端

認證後端是一個實現兩個必需方法的類:get_user(user_id)和authenticate(** credentials),以及一組可選的權限相關授權方法。 get_user方法需要一個user_id - 可以是一個用戶名,數據庫ID或其他,但必須是你的用戶對象的主鍵 - 並返回一個用戶對象。 身份驗證方法將憑據作為關鍵字參數。 大多數情況下,它看起來像這樣:

class MyBackend(object):
    def authenticate(self, username=None, password=None):
        # Check the username/password and return a User.
        ...

但它也可以驗證令牌,如下所示:

class MyBackend(object):
    def authenticate(self, token=None):
        # Check the token and return a User.
        ...

無論哪種方式,身份驗證都應該檢查它獲取的憑據,並且如果證書有效,它應該返回與這些憑證相匹配的用戶對象。 如果它們無效,則應返回無。
Django管理系統與本章開頭描述的Django用戶對象緊密耦合。

現在,處理這個問題的最好方法是為每個存在於後端的用戶創建一個Django User對象(例如,在您的LDAP目錄,外部SQL數據庫等中)。您可以編寫腳本來執行此操作 或者您的身份驗證方法可以在用戶首次登錄時執行此操作。

以下是一個示例後端,它會根據settings.py文件中定義的用戶名和密碼變量進行身份驗證,並在用戶首次進行身份驗證時創建一個Django用戶對象:

from django.conf import settings
from django.contrib.auth.models import User, check_password

class SettingsBackend(object):
    """
    Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD.

    Use the login name, and a hash of the password. For example:

    ADMIN_LOGIN = ‘admin‘
    ADMIN_PASSWORD = ‘sha1$4e987$afbcf42e21bd417fb71db8c66b321e9fc33051de‘
    """

    def authenticate(self, username=None, password=None):
        login_valid = (settings.ADMIN_LOGIN == username)
        pwd_valid = check_password(password, settings.ADMIN_PASSWORD)
        if login_valid and pwd_valid:
            try:
                user = User.objects.get(username=username)
            except User.DoesNotExist:
                # Create a new user. Note that we can set password
                # to anything, because it won‘t be checked; the password
                # from settings.py will.
                user = User(username=username, password=‘password‘)
                user.is_staff = True
                user.is_superuser = True
                user.save()
            return user
        return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None 

處理自定義後端中的授權
自定義授權後端可以提供他們自己的權限。 用戶模型會將權限查找函數(get_group_permissions(),get_all_permissions(),has_perm()和has_module_perms())委托給實現這些函數的任何驗證後端。 賦予用戶的權限將是所有後端返回的所有權限的超集。 也就是說,Django向任何一個後端授予的用戶授予權限。

如果後端在has_perm()或has_module_perms()中引發PermissionDenied異常,授權將立即失敗,Django將不檢查後面的後端。 上面的簡單後端可以簡單地為管理員實現權限:

class SettingsBackend(object):
    ...
    def has_perm(self, user_obj, perm, obj=None):
        if user_obj.username == settings.ADMIN_LOGIN:
            return True
        else:
            return False 

這給上面例子中授予訪問權限的用戶提供了完全的權限。 請註意,除了給予相關用戶功能的相同參數之外,後端授權功能都將用戶對象(可能是匿名用戶)作為參數。

完整的授權實現可以在django / contrib / auth / backends.py中的ModelBackend類中找到,它是默認的後端,它大部分時間都會查詢auth_permission表。 如果您希望僅為後端API的一部分提供自定義行為,則可以利用Python繼承和子類ModelBackend,而不是在自定義後端中實現完整的API。

匿名用戶授權

匿名用戶是未經過身份驗證的用戶,即他們未提供有效的身份驗證詳細信息。 但是,這並不一定意味著他們無權做任何事情。 在最基本的層面上,大多數網站授權匿名用戶瀏覽大部分網站,並且許多網站允許匿名發布評論等。

Django的權限框架沒有地方為匿名用戶存儲權限。 但是,傳遞給身份驗證後端的用戶對象可能是django.contrib.auth.models.AnonymousUser對象,允許後端為匿名用戶指定自定義授權行為。

這對於可重用應用程序的作者特別有用,他們可以將授權的所有問題委托給auth後端,而不需要設置,例如控制匿名訪問。

對非活躍用戶授權

非活躍用戶是經過身份驗證的用戶,但其屬性is_active設置為False。 但是,這並不意味著他們無權做任何事情。 例如,他們被允許激活他們的帳戶。

對權限系統中的匿名用戶的支持允許匿名用戶有權執行某些操作,而不活動的經過身份驗證的用戶則不能這樣做。 不要忘記在你自己的後端權限方法中測試用戶的is_active屬性。

處理對象權限

Django的權限框架為對象權限奠定了基礎,但核心中沒有實現它。 這意味著檢查對象權限將始終返回False或一個空列表(取決於執行的檢查)。 身份驗證後端將為每個對象相關的授權方法接收關鍵字參數obj和user_obj,並可以根據需要返回對象級別權限。

自定義權限

要為給定的模型對象創建自定義權限,請使用權限模型元屬性。 本示例任務模型創建三個自定義權限,即用戶可以使用或不能使用Task實例執行的操作,具體針對您的應用程序:

class Task(models.Model):
    ...
    class Meta:
        permissions = (
            ("view_task", "Can see available tasks"),
            ("change_task_status", "Can change the status of tasks"),
            ("close_task", "Can remove a task by setting its status as   
              closed"),
        )

這樣做的唯一方法是在運行manage.py遷移時創建這些額外的權限。 當用戶試圖訪問應用程序提供的功能(查看任務,更改任務狀態,關閉任務)時,您的代碼負責檢查這些權限的值。繼續上面的示例,以下示例將檢查用戶 可能會查看任務:

user.has_perm(‘app.view_task‘)
擴展現有的用戶模型

有兩種方法可以擴展默認用戶模型,而不用替換自己的模型。 如果您需要的更改是純粹的行為,並且不需要對存儲在數據庫中的內容進行任何更改,則可以基於用戶創建代理模型。 這允許代理模型提供的任何功能,包括默認排序,自定義管理器或自定義模型方法。

如果您希望存儲與用戶相關的信息,則可以使用包含字段的模型的一對一關系以獲取更多信息。 這種一對一模式通常稱為配置文件模型,因為它可能存儲有關站點用戶的非auth相關信息。 例如,您可以創建一個Employee模型:

from django.contrib.auth.models import User

class Employee(models.Model):
   user = models.OneToOneField(User)
   department = models.CharField(max_length=100)

假設現有員工Fred Smith擁有User和Employee模型,則可以使用Django的標準相關模型約定訪問相關信息:

>>> u = User.objects.get(username=‘fsmith‘)
>>> freds_department = u.employee.department 

要將配置文件模型的字段添加到admin的用戶頁面,請在應用程序的admin.py中定義InlineModelAdmin(對於本示例,我們將使用StackedInline),並將其添加到UserAdmin類,該類用User類註冊:

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User

from my_user_profile_app.models import Employee

# Define an inline admin descriptor for Employee model
# which acts a bit like a singleton
class EmployeeInline(admin.StackedInline):
    model = Employee
    can_delete = False
    verbose_name_plural = ‘employee‘

# Define a new User admin
class UserAdmin(UserAdmin):
    inlines = (EmployeeInline, )

# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)

這些配置文件模型在任何方面都不是特別的 - 它們只是恰好與用戶模型具有一對一鏈接的Django模型。因此,創建用戶時不會自動創建,但可以根據需要使用django.db.models.signals.post_save創建或更新相關模型。

請註意,使用相關模型會產生額外的查詢或連接以檢索相關數據,根據您的需要,替換用戶模型並添加相關字段可能是更好的選擇。但是,項目應用程序中默認用戶模型的現有鏈接可能會導致額外的數據庫負載。

代替自定義用戶模型

某些類型的項目可能具有身份驗證要求,因此Django的內置User模型並不總是適合的。例如,在一些網站上,使用電子郵件地址作為您的身份標記而不是用戶名更有意義。 Django允許您通過為引用自定義模型的AUTH_USER_MODEL設置提供值來覆蓋默認的用戶模型:

`AUTH_USER_MODEL = ‘books.MyUser‘`

此虛線對描述了Django應用程序的名稱(它必須位於INSTALLED_APPS中),以及您希望用作用戶模型的Django模型的名稱。

改變AUTH_USER_MODEL對你的Django項目有很大的影響,特別是你的數據庫結構。 例如,如果在運行遷移後更改AUTH_USER_MODEL,則必須手動更新數據庫,因為它會影響許多數據庫表關系的構建。 除非有充分理由這樣做,否則不應更改AUTH_USER_MODEL。

盡管有上述警告,但Django完全支持自定義用戶模型,但完整的解釋超出了本書的範圍。 Django項目網站上提供了一個完全符合管理員要求的自定義用戶應用程序示例,以及有關自定義用戶模型的全面文檔。

轉載自:https://www.jianshu.com/p/5806ff9c0cc5

在Django中定制身份驗證