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')

 

注:上述的兩個也是不驗證是否為活躍用戶的,所以使用的時候要小心。
 
 
 
 
 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM