django-訪問控制

django自帶的用戶認證系統提供了訪問控制的的功能。
 
1.只容許登陸的用戶登陸
 
django的用戶可分爲兩類,一是可認證的用戶,也就是在django.contrib.auth.models.User中註冊了的;另外一種是匿名用戶 django.contrib.auth.models.AnonymousUser,每一個訪問的未登陸的用戶都是該類的一個實例,而匿名用戶是沒法認證的,即 is_authenticated 方法永遠返回 False,或者 is_anonymous返回True,咱們能夠在代碼邏輯中實現對匿名用戶進行判斷,而後拒絕其訪問(403),或者重定向到登陸頁面等。
 
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')
    # ...

 

因爲這是一個常見的需求,因此django提供了一個裝飾器來實現這個功能。
 
from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
    ...

 

 
這樣大大的簡化了工做。
 
  login_required(redirect_field_name='next', login_url=None) 
 
若用戶沒有登陸的話, 其將沒法訪問被裝飾的視圖,而是重定向到登陸頁面,這個登陸頁面可使用login_url參數指定,而且能夠接受命名url的方式,如:@login_required(login_url='login'),固然前提是要有相應的命名的url。若是沒有給定這個參數,將使用 settings.LOGIN_URL的值。
 
 
LOGIN_URL
Default: '/accounts/login/'
 
The URL where requests are redirected for login, especially when using the  login_required() decorator.
 
This setting also accepts  named URL patterns which can be used to reduce configuration duplication since you don’t have to define the URL in two places (settings and URLconf).
 
能夠看見其有默認值,若是你不給參數,且登陸地址不是這個默認值,將觸發404錯誤,也就是仍是重定向到那個頁面去了,只是找不到而已。若強制重寫爲None,其會觸發TypeError,若DEBUG=False,則應該是500系列的服務器錯誤。
 
可是,在重定向的時候,並非單純跳轉,而是會帶一個next查詢參數例如:
 
 
 
這樣你就能夠獲取登陸前想要訪問的頁面(這裏就是/account/change_info頁面了),而後在登陸後重定向回去,而不用盲目重定向到首頁,用戶體驗會更好點。
 
下面就是登陸視圖中所作的配合:
 
next_to = request.GET.get('next', None)  # 獲取是否有next的重定向,是一個相對路徑,不含方案和域名
if next_to:
    return redirect(next_to)

 

固然你也能夠改變redirect_field_name來改變next這個名稱,固然在登陸視圖裏也要作想要的調整,也能夠將其設爲None來取消附帶參數的行爲。
 
 
注意:login_required 並不會檢查用戶是否處於活躍狀態(is_active),而處理用戶登陸的默認後臺模板在1.10以前並不會拒絕非活躍用戶登陸,而1.10版本就會。這意味着若是你使用的版本低於1.10,你必須在代碼邏輯中拒絕非活躍用戶登陸。
 
if user.is_active:  # 若用戶是活躍的,即未凍結的,在1.10以前凍結用戶默認也能登陸,因此須要本身認證
    login(request, user)    # 登陸
......    #其餘處理
else:
    return HttpResponse('用戶被凍結')

 

 
2.只容許staff身份的用戶訪問某個視圖
 
django一樣提供了一個便捷的裝飾器來實現這個功能:
 
  staff_member_required(redirect_field_name='next', login_url='admin:login') 
 
 
能夠看到其和上述的 login_required 參數上幾乎同樣,只是默認值有些許不一樣,而在用法上也是同樣的,但並無 settings.LOGIN_URL之類的設置層面上的退路。要注意一點,由於其默認是重定向至admin的登陸頁面,若要經過複雜化url的方式來隱藏入口的時候,要當心其會暴露該url。
 
This decorator is used on the admin views that require authorization. A view decorated with this function will having the following behavior:
這個裝飾器已經被admin的視圖所使用了,其行爲以下:
 
 
 
  • If the user is logged in, is a staff member (User.is_staff=True), and is active (User.is_active=True), execute the view normally.
若是用戶已經登陸,且爲staff身份,而且是活躍的,則正常執行所裝飾的視圖。
 
  • Otherwise, the request will be redirected to the URL specified by the login_url parameter, with the originally requested path in a query string variable specified by redirect_field_name. For example: /admin/login/?next=/admin/polls/question/3/.
不然,將會重定向到login_url,並帶查詢參數。
 
Example usage:
用例:
 
 
from django.contrib.admin.views.decorators import staff_member_required

@staff_member_required
def my_view(request):
    ...

 

能夠看到其使用方法和 login_required()基本是同樣的。
 

3.簡單的函數測試驗證法
 
django提供了一個裝飾器,讓咱們能夠自定義一個簡單的驗證函數,只有經過該驗證函數以後才能訪問指定的視圖。
 
  user_passes_test(func[, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME]) 
 
能夠看到其比上面的兩個裝飾器多了一個參數,這個參數就是用指定驗證函數的。
 
例如,我想要驗證某個用戶的郵箱是否符合我想要的格式:
 
原始的驗證法:
 
from django.shortcuts import redirect

def my_view(request):
    if not request.user.email.endswith('@example.com'):
        return redirect('/login/?next=%s' % request.path)
    # ...
 
在視圖函數中驗證其是否以@example.com結尾。
 
下面是裝飾器驗證法:
 
from django.contrib.auth.decorators import user_passes_test

def email_check(user):
    return user.email.endswith('@example.com')

@user_passes_test(email_check)
def my_view(request):
    ...

 

注意:email_check函數其本質上也是返回布爾值,因此在自定義函數的時候,返回True表示經過,False表示不經過。不經過則重定向到登陸頁面,其餘細節和以前的兩個裝飾器同樣。
 
 

基於類的視圖的實現
 
基於類的視圖在實現login_required的行爲時,須要繼承LoginRequiredMixin這個類,並將其放在繼承樹的最左邊,同時相應的實如今類中書寫,例如:
 
from django.contrib.auth.mixins import LoginRequiredMixin

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

 

 
注:這裏是View是通用視圖,這裏並沒要導入的代碼,詳情請參考基於類的視圖。
 
還有更多的屬性可供使用,可參考  AccessMixin 這個類。
 
 
實現user_passes_test行爲也是相似的,首先繼承UserPassesTestMixin這個類(在最左邊),而後在類的裏面重寫test_func方法,該方法也是返回布爾值。
 
New in Django 1.9.
 
from django.contrib.auth.mixins import UserPassesTestMixin

class MyView(UserPassesTestMixin, View):

    def test_func(self):
        return self.request.user.email.endswith('@example.com')

 

注:上述的兩個也是不驗證是否爲活躍用戶的,因此使用的時候要當心。
相關文章
相關標籤/搜索