基本代碼結構 url.py: views.py: 說明: has_permission方法的返回值是布爾類型,True表示許可權通過,False表示許可權拒絕 上面的基本結構是做局部的類的許可權判斷方式,全局許可權判斷後文介紹。 permission_classes屬性變數同樣也是一個列表,列表元素是許可權判 ...
基本代碼結構
url.py:
from django.conf.urls import url, include from app import views urlpatterns = [ url(r'^test/', views.TestView.as_view()), ]
views.py:
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.request import Request from rest_framework import exceptions class MyPermission(object): def has_permission(request, self): ''' 許可權代碼編寫區域 ''' return True #許可權通過 如果許可權不通過 返回False class TestView(APIView): permission_classes = [MyPermission, ] def get(self, request, *args, **kwargs): pass def post(self, request, *args, **kwargs): pass ''' 等等一系列的視圖功能方法 '''
說明:
-
- has_permission方法的返回值是布爾類型,True表示許可權通過,False表示許可權拒絕
- 上面的基本結構是做局部的類的許可權判斷方式,全局許可權判斷後文介紹。
- permission_classes屬性變數同樣也是一個列表,列表元素是許可權判斷類。
源碼分析
其實許可權的源碼流程跟認證的流程基本相同。還是要抓住通過源碼要想知道什麼,不然就會陷入浩如煙海的源碼之中。
-
為什麼會使用permission_classes屬性變數?
python 的面向對象編程中,我們首先要執行的方法肯定是dispatch方法,所以我們的分析入口就是dispatch方法,在dispatch方法中,可以看到,通過initialize_request方法將django原生的request進行了一次封裝。由initialize_request方法的實現過程可以看出,將其封裝實例化成了一個Request對象。但許可權判斷並沒有像認證一樣初始化到了Request對象中,但對django原生的request封裝還是需要強調的,因為編寫代碼的過程中對django原生的request的使用是必不可免的。
同樣的,許可權判斷的具體過程跟認證一樣,也是在dispatch方法中所調用的initial方法中實現。再跳轉到initial方法中去。
在initial方法中,可以看到許可權判斷的方法,沒錯,就是通過check_permissions方法實現的。再跳轉到這個方法中去。
在check_permissions方法中,就可以看到許可權的判斷就是通過這個for迴圈實現的。正因為在業務代碼中可能存在若幹種類型的許可權判斷,所以才會通過迴圈去執行我們定義好的許可權判斷類來完成多個許可權體系的判斷功能。這樣,我們可以感覺到這裡的“self.get_permissions()”的返回值應該就是我們在視圖類中賦值過的permissions_classes屬性變數的值。那就跳轉到這個方法中去看看吧。
在get_permissions方法中看到,跟認證一樣,返回值同樣是一個列表生成式,而這個列表生成式使用的屬性變數正是我們賦值過的permission_classes,跟我們之前的猜測完全一致。綜上所述,我們為了讓drf介面源碼使用上我們自己定義的許可權判斷類,那我們就必須按照源碼中寫的藉口,將permission_classes屬性變數賦值
-
在許可權判斷類中為什麼會定義一個名稱為has_permission的方法?
回到check_permissions方法中,我們看if判斷句,前面剛剛說過,在for中的permission其實就是我們自己定義的許可權判斷類,那麼在if句中的“.has_permission(request,self)”不就應該就是Mypermission類中的方法嗎?所以,我們自己定義的Mypermission類中一定要實現has_permission這個方法。(要註意這個方法的參數)
-
has_permission方法中,為什麼返回值為布爾值?
還是跟上一個問題一樣的,在上圖中的if句中,我們可以看到“permission.has_permission(request, self)”的返回值不就是布爾值嗎,這個返回值不就是has_permission方法返回值嗎?當返回值為False時,就會執行if句中的代碼,來拋出異常。
實例
from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'^test/', TestView.as_view()), ]urls.py
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.permissions import BasePermission from rest_framework.request import Request from rest_framework import exceptions token_list = [ 'sfsfss123kuf3j123', 'asijnfowerkkf9812', ] class TestAuthentication(BaseAuthentication): def authenticate(self, request): """ 用戶認證,如果驗證成功後返回元組: (用戶,用戶Token) :param request: :return: None,表示跳過該驗證; 如果跳過了所有認證,預設用戶和Token和使用配置文件進行設置 self._authenticator = None if api_settings.UNAUTHENTICATED_USER: self.user = api_settings.UNAUTHENTICATED_USER() # 預設值為:匿名用戶 else: self.user = None if api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 預設值為:None else: self.auth = None (user,token)表示驗證通過並設置用戶名和Token; AuthenticationFailed異常 """ val = request.query_params.get('token') if val not in token_list: raise exceptions.AuthenticationFailed("用戶認證失敗") return ('登錄用戶', '用戶token') def authenticate_header(self, request): """ Return a string to be used as the value of the `WWW-Authenticate` header in a `401 Unauthenticated` response, or `None` if the authentication scheme should return `403 Permission Denied` responses. """ pass class TestPermission(BasePermission): message = "許可權驗證失敗" def has_permission(self, request, view): """ 判斷是否有許可權訪問當前請求 Return `True` if permission is granted, `False` otherwise. :param request: :param view: :return: True有許可權;False無許可權 """ if request.user == "管理員": return True # GenericAPIView中get_object時調用 def has_object_permission(self, request, view, obj): """ 視圖繼承GenericAPIView,併在其中使用get_object時獲取對象時,觸發單獨對象許可權驗證 Return `True` if permission is granted, `False` otherwise. :param request: :param view: :param obj: :return: True有許可權;False無許可權 """ if request.user == "管理員": return True class TestView(APIView): # 認證的動作是由request.user觸發 authentication_classes = [TestAuthentication, ] # 許可權 # 迴圈執行所有的許可權 permission_classes = [TestPermission, ] def get(self, request, *args, **kwargs): # self.dispatch print(request.user) print(request.auth) return Response('GET請求,響應內容') def post(self, request, *args, **kwargs): return Response('POST請求,響應內容') def put(self, request, *args, **kwargs): return Response('PUT請求,響應內容')views.py
擴展:全局許可權
同樣,跟全局認證一樣,我們只需要在settings配置文件中添加配置項即可。然後,我們仍然需要將我們自定義的許可權類也寫到我們在跟views.py同級目錄下新建的文件夾(我習慣叫utils)中的許可權判斷文件(permision.py)中去。
REST_FRAMEWORK = { "DEFAULT_PERMISSION_CLASSES" :['api.utils.permission.Mypermission',] }
Mypermission就是我們寫在utils文件夾中permission.py文件中的一個許可權類。
註意:如果有部分類不需要許可權判斷的話,可以在Mypermission類中添加“permission_classes = []”,即可。