今天我們來看看rest_framework的APIView的權限驗證過程是怎麼走的。
一、 與認證的入口相似,權限驗證也是從APIView的dispatch()到initial()方法,再到check_permissions(),通過返回True或者False來判斷請求是否通過了權限驗證:
def initial(self, request, *args, **kwargs):
self.format_kwarg = self.get_format_suffix(**kwargs)
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme
# 認證
self.perform_authentication(request)
# 權限
self.check_permissions(request)
# 節流
self.check_throttles(request)
二、 在check_permissions方法中,遍歷了視圖的get_permissions方法的返回值(返回的是列表形式存儲的權限驗證類的實例),並運行它們的has_permission方法。
def check_permissions(self, request):
for permission in self.get_permissions(): # get_permissions方法返回了權限類的列表推導式
if not permission.has_permission(request, self): # 遍歷權限類並執行has_permission方法
self.permission_denied(
request, message=getattr(permission, 'message', None)
)
- get_permissions從定義的視圖中拿到permission_classes(列表格式,可包含多個權限類),並使用列表推導式將實例化的對象存放在列表並返回給check_permissions使用。
def get_permissions(self):
return [permission() for permission in self.permission_classes]
三、 如果權限類的has_permission返回True,那麼本次循環不做任何操作,繼續執行下一個權限類的has_permission方法。如果全部返回True,那麼本次權限驗證全部通過,否則執行視圖的permission_denied方法,
def permission_denied(self, request, message=None):
if request.authenticators and not request.successful_authenticator:
raise exceptions.NotAuthenticated()
raise exceptions.PermissionDenied(detail=message) # 拋出權限拒絕的錯誤
可以在視圖類中添加message屬性來定製權限驗證失敗後返回的信息。
四、 由APIView源碼可以知道,權限類可以在視圖類的permission_classes中設定,以列表的格式。
from rest_framework.permissions import AllowAny
from rest_framework.authentication import BaseAuthentication
class MyView(APIView):
authentication_classes = [BaseAuthentication,] # 認證類
permission_classes = [AllowAny,] # 權限類
def get(self, request, *args, **kwargs):
…………
rest_framework中內置了8中認證類:BasePermission、AllowAny、IsAuthenticated、IsAdminUser、IsAuthenticatedOrReadOnly、DjangoModelPermissions、DjangoModelPermissionsOrAnonReadOnly、DjangoObjectPermissions。
五、 與認證類同理,權限類如果設置在項目的配置文件中,就有了全局權限驗證的效果:
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": ["rest_framework.authentication.BaseAuthentication",], # 認證類
"DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.AllowAny"] # 權限類
}
六、 如果想要自定義權限類,必須包含兩個方法:has_permission(self, request, view)、has_object_permission(self, request, view, obj)。注意:方法中傳遞的參數也是不可省略的。
class Mypermissions(object):
def has_permission(self, request, view):
# VIP用戶方可訪問
if request.user.group == 'VIP':
return True
return False
def has_object_permission(self, request, view, obj):
return True