1. 程式人生 > >django認證系統 Authentication

django認證系統 Authentication

Django自帶一個使用者認證系統,用於處理使用者賬戶、群組、許可和基於cookie的使用者會話。

Django的認證系統包含了身份驗證和許可權管理兩部分。簡單地說,身份驗證用於核實某個使用者是否合法,許可權管理則是決定一個合法使用者具有哪些許可權。往後,‘認證’這個詞同時代指上面兩部分的含義。

Django的認證系統主要包括下面幾個部分:

  • 使用者
  • 許可
  • 可配置的密碼雜湊系統
  • 用於使用者登入或者限制訪問的表單和檢視工具
  • 可插拔的後臺系統

類似下面的問題,不是Django認證系統的業務範圍,請使用第三方工具:

  • 密碼強度檢查
  • 登入請求限制
  • 第三方認證

預設情況下,使用django-admin startproject命令後,認證相關的模組已經自動新增到settings檔案內了,如果沒有的話,請手動新增。

INSTALLED_APPS配置項中新增:

  1. 'django.contrib.auth': 包含認證框架的核心以及預設模型
  2. 'django.contrib.contenttypes':內容型別系統,用於給模型關聯許可

在MIDDLEWARE配置項中新增:

  1. SessionMiddleware:通過請求管理會話
  2. AuthenticationMiddleware:將會話和使用者關聯

當配置正確後,執行manage.py migrate

命令,建立使用者認證系統相關的資料庫表以及分配預定義的許可權。

一、使用者物件

使用者物件是Django認證系統的核心!在Django的認證框架中只有一個使用者模型也就是User模型,它位於django.contrib.auth.models

本節內容敘述的所有功能,都是基於這個User模型的,和這個User模型沒有任何關係的自定義使用者模型是無法使用Django認證系統的功能的!

使用者模型主要有下面幾個欄位:

  • username
  • password
  • email
  • first_name
  • last_name

1. 建立使用者

要建立一個新使用者,最直接的辦法是使用create_user()

方法:

>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user('john', '[email protected]', 'johnpassword') # 這時,user是一個User類的例項,已經儲存在了資料庫內,你可以隨時修改它的屬性,例如: >>> user.last_name = 'Lennon' >>> user.save() 

如果你已經啟用了Django的admin站點,你也可以在後臺建立使用者。

2. 建立超級使用者

使用createsuperuser命令,建立超級使用者:

$ python manage.py createsuperuser
或者
$ python manage.py createsuperuser --username=joe --email[email protected]

根據提示輸入名字、密碼和郵箱地址。密碼要有一定強度

3. 修改密碼

Django預設會對密碼進行加密,因此,不要企圖對密碼進行直接操作。

要修改密碼,有兩個辦法:

  • 使用命令列: python manage.py changepassword username。如果不提供使用者名稱,則會嘗試修改當前系統使用者的密碼。
  • 使用set_password()方法:
from django.contrib.auth.models import User
u = User.objects.get(username='john') u.set_password('new password') u.save() 

同樣可以在admin中修改密碼。Django提供了views和forms,方便使用者自己修改密碼。 修改密碼後,使用者的所有當前會話將被登出。

4. 使用者驗證

利用authenticate()方法,對使用者進行驗證。該方法通常接收username與password作為引數。要注意的是,認證的後端可能有好幾個,有一項認證通過則返回一個User類物件,一項都沒通過或者丟擲了PermissionDenied異常,則返回一個None。例如:

from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret') if user is not None: # A backend authenticated the credentials else: # No backend authenticated the credentials 

二、 許可權與授權

Django提供了一個簡單的許可權系統,並且已經用於它的admin站點,當然你也可以在你的程式碼中使用。

User模型的物件有兩個多對多的欄位:groups和user_permissions,可以像下面這樣訪問他們:

myuser.groups.set([group_list])
myuser.groups.add(group, group, ...)
myuser.groups.remove(group, group, ...)
myuser.groups.clear()
myuser.user_permissions.set([permission_list])
myuser.user_permissions.add(permission, permission, ...)
myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear()

1. 預設許可權

預設情況下,使用manage.py migrate命令時,Django會給每個已經存在的model新增預設的許可權。 假設你現在有個app叫做foo,有個model叫做bar,使用下面的方式可以測試預設許可權:

add: user.has_perm('foo.add_bar') change: user.has_perm('foo.change_bar') delete: user.has_perm('foo.delete_bar') 

2. 使用者組

Django提供了一個django.contrib.auth.models.Group模型,該model可用於給使用者分組,實現批量管理。使用者和組屬於多對多的關係。使用者自動具有所屬組的所有許可權。

3. 在程式碼中建立許可權

例如,為myapp中的BlogPost模型新增一個can_publish許可權。

from myapp.models import BlogPost
from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType content_type = ContentType.objects.get_for_model(BlogPost) permission = Permission.objects.create( codename='can_publish', name='Can Publish Posts', content_type=content_type, ) 

然後,你可以通過User模型的user_permissions屬性或者Group模型的permissions屬性為使用者新增該許可權。

4. 許可權快取

許可權檢查後,會被快取在使用者物件中。參考下面的例子:

from django.contrib.auth.models import Permission, User from django.shortcuts import get_object_or_404 def user_gains_perms(request, user_id): user = get_object_or_404(User, pk=user_id) # any permission check will cache the current set of permissions user.has_perm('myapp.change_bar') permission = Permission.objects.get(codename='change_bar') user.user_permissions.add(permission) # Checking the cached permission set user.has_perm('myapp.change_bar') # False # Request new instance of User # Be aware that user.refresh_from_db() won't clear the cache. user = get_object_or_404(User, pk=user_id) # Permission cache is repopulated from the database user.has_perm('myapp.change_bar') # True ... 

三、 在檢視中認證使用者

Django使用session和中介軟體關聯請求物件中和認證系統。

每一次請求中都包含一個request.user屬性,表示當前使用者。如果該使用者未登陸,該屬性的值是一個AnonymousUser例項(匿名使用者),如果已經登入,該屬性就是一個User模型的例項。

可以使用is_authenticated方法進行判斷,如下:

if request.user.is_authenticated:
# Do something for authenticated users.
...
else:
    # Do something for anonymous users.
    ...

1. 如何登入使用者

在檢視中,使用認證系統的login()方法登入使用者。它接收一個HttpRequest引數和一個User物件引數。該方法會把使用者的ID儲存在Django的session中。下面是一個認證和登陸的例子:

from django.contrib.auth import authenticate, login def my_view(request): username = request.POST['username'] password = request.POST['password'] user = authenticate(username=username, password=password) if user is not None: login(request, user) # 跳轉到成功頁面 ... else: # 返回一個非法登入的錯誤頁面 ... 

2. 如何登出使用者

logout(request)[source]:

from django.contrib.auth import logout

def logout_view(request): logout(request) # Redirect to a success page. 

注意,被logout的使用者如何沒登入,不會丟擲錯誤。 一旦logout,當前請求中的session資料都會被清空。

3. 限制使用者的訪問許可權

很多時候,我們要區分已登入使用者和未登入使用者,只對登入的使用者開放一些頁面或功能,限制未登入使用者的行為。辦法有很多,下面是主要幾種:

1.原始的辦法

如果使用者未登入,重定向到登入頁面,如下所示:

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)) # ... 

或者顯示一個錯誤資訊:

from django.shortcuts import render

def my_view(request): if not request.user.is_authenticated: return render(request, 'myapp/login_error.html') # ... 

2. 使用裝飾器

原型:login_required(redirect_field_name='next', login_url=None)[source]

被該裝飾器裝飾的檢視,強制要求使用者必須登入後才可以訪問。

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request): ... 

該裝飾器工作機制:

  • 如果使用者未登陸,重定向到settings.LOGIN_URL,傳遞當前絕對路徑作為url字串的引數,例如:/accounts/login/?next=/polls/3/
  • 如果使用者已經登入,執行正常的檢視

此時,預設的url中使用的引數是“next”,如果你想使用自定義的引數,請修改login_required()redirect_field_name引數,如下所示:

from django.contrib.auth.decorators import login_required

@login_required(redirect_field_name='my_redirect_field') def my_view(request): ... 

如果你這麼做了,你還需要重新定製登入模板,因為它引用了redirect_field_name變數。

login_required()裝飾器還有一個可選的longin_url引數。例如:

from django.contrib.auth.decorators import login_required

@login_required(login_url='/accounts/login/') def my_view(request): ... 

注意:如果不指定login_url引數,請確保你的settings.LOGIN_URL和登陸檢視保持正確的關聯。例如:

from django.contrib.auth import views as auth_views url(r'^accounts/login/$', auth_views.login), 

3. 使用LoginRequired mixin

通過繼承LoginRequiredMixin類的方式限制使用者。在多繼承時,該類必須是最左邊的父類。

from django.contrib.auth.mixins import LoginRequiredMixin

class MyView(LoginRequiredMixin, View): login_url = '/login/' redirect_field_name = 'redirect_to' 

4. 進行測試,根據結果決定動作

也可以直接在檢視中進行過濾:

from django.shortcuts import redirect

def my_view(request): if not request.user.email.endswith('@example.com'): return redirect('/login/?next=%s' % request.path) # ... 

上面根據使用者的郵箱地址,判斷使用者的許可權。

5. 使用許可權需求裝飾器

Django內建了一個permission_required()裝飾器,使用者根據使用者許可權,決定檢視的訪問許可權,如下所示:

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote') def my_view(request): ... 

許可權的格式是<app label>.<permission codename>

該裝飾器還有一個可選的longin_url引數:

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote', login_url='/loginpage/') def my_view(request): ... 

4. 認證檢視

Django為我們提供了一系列認證相關的檢視,可以直接拿來用,這樣你就不需要自己寫登入、登出、註冊等檢視。但是,但是,Django沒有為認證檢視提供預設的模板,你需要自己寫......。

所以,除非懶癌發作,還是老老實實自己寫認證相關的檢視、路由和模板吧。個人認為類似跟實際生產環境結合非常緊密的檢視,根本不需要這種雞肋的內建檢視,到最後,你發現還是要自己寫才能滿足需求。

所以,後面的部分就不贅述了!