django-存取控制,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 settingsfrom django.shortcuts import redirectdef my_view(request): if not request.user.is_authenticated: return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path)) # ...
以上就是在代碼中重新導向到登入頁面的做法,也可以返回錯誤資訊:
from django.shortcuts import renderdef 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_requireddef 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查詢參數例如: http://127.0.0.1:8000/account/login/?next=/account/change_info 這樣你就可以擷取登入前想要訪問的頁面(這裡就是/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_requireddef my_view(request): ...
可以看到其使用方法和login_required()基本是一樣的。
3.簡單的函數測實驗證法
django提供了一個裝飾器,讓我們可以自訂一個簡單的驗證函式,只有通過該驗證函式之後才能訪問指定的視圖。 user_passes_test(func[, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME]) 可以看到其比上面的兩個裝飾器多了一個參數,這個參數就是用指定驗證函式的。 例如,我想要驗證某個使用者的郵箱是否符合我想要的格式: 原始的驗證法:
from django.shortcuts import redirectdef 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_testdef 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 LoginRequiredMixinclass 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 UserPassesTestMixinclass MyView(UserPassesTestMixin, View): def test_func(self): return self.request.user.email.endswith('@example.com')
註:上述的兩個也是不驗證是否為活躍使用者的,所以使用的時候要小心。