概述
认证组件 = [认证类, 认证类, 认证类...]
- 执行每个认证类实例的authenticate()方法
- 认证成功或失败,不会执行后续的认证类实例
- 返回
None, 执行后续认证类实例的authenticate()方法
权限组件 = [权限类,权限类,权限类...]
- 执行每个权限类实例的has_permission()方法
- 执行全部的权限类实例
- 默认情况下,保证所有权限类实例的has_permission()方法都返回
True。只要有一个权限类返回False,则不能获取权限
如果希望权限组件可以像认证组件一样使用"或"而不是"且"的关系,可以在源码基础之上扩展+自定义。
权限组件应用
自定义权限类
from rest_framework.permissions import BasePermission
class Mypermission(Basepermission):
# 权限类必须有message属性
def has_permission(self, request, view):
# 根据请求的数据,进行校验
自定义的权限类继承自BasePermission
class BasePermission(metaclass=BasePermissionMetaclass):
# 所有权限类都应从中继承的基类。
def has_permission(self, request, view):
# 如果授予了权限,则返回`True`,否则返回`False`
return True
def has_object_permission(self, request, view, obj):
# 如果授予了权限,则返回`True`,否则返回`False`
return True
给视图类添加自定义的权限组件
class OrderView(APIView):
permission_classes = [MyPermission, ]
...
也可以在全局设置默认的权限组件
REST_FRAMEWORK = {
...
DEFAULT_PERMISSION_CLASSES: [
"app01.permissions.MyPermission",
...
],
...
}
源码执行流程
class APIView(View):
...
permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
...
def dispatch(self, request, *args, **kwargs):
...
# 对request进行封装
request = self.initialize_request(request, *args, **kwargs)
...
try:
# 执行权限的校验
self.initial(request, *args, **kwargs)
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
def initial(self, request, *args, **kwargs):
self.perform_authentication(request)
# 执行权限组件
# 此时已经认证成功或者是匿名用户
self.check_permissions(request)
self.check_throttles(request)
def check_permissions(self, request):
# 检查是否应该允许该请求
# 如果请求不被允许,则引发适当的异常。
# 对每个权限类实例对请求进行校验
for permission in self.get_permissions():
if not permission.has_permission(request, self):
self.permission_denied(
request,
message=getattr(permission, 'message', None),
# 自定义的权限类应该有message属性,内容是错误信息
code=getattr(permission, 'code', None)
# 同样可以设置自定义权限类的code属性
)
def get_permissions(self):
# 返回权限类实例的列表
return [permission() for permission in self.permission_classes]
def permission_denied(self, request, message=None, code=None):
# 如果请求没有被允许,决定抛出哪种异常
# 认证成功后,request.authenticators就是
if request.authenticators and not request.successful_authenticator:
raise exceptions.NotAuthenticated()
raise exceptions.PermissionDenied(detail=message, code=code)
class Request:
...
@property
def successful_authenticator(self):
# 返回被用于认证请求的认证类实例,或者None
if not hasattr(self, '_authenticator'):
with wrap_attributeerrors():
self._authenticate()
return self._authenticator
如果希望只要有一个权限类通过即可,可以自定义:
class APIView(View):
...
def check_permissions(self, request):
for permission in self.get_permissions():
# 这里是修改的地方
# 只要有一个permission.has_permission()为True,就return
if permission.has——permission(request, self):
return
# 如果一个权限类都没通过,那就抛出异常
self.permission_denied(
request,
# 这里的permission是循环中的最后一个权限类实例
# 也可以自己选择哪个认证类的message和code
message=getattr(permission, 'message', None),
# 自定义的权限类应该有message属性,内容是错误信息
code=getattr(permission, 'code', None)
# 同样可以设置自定义权限类的code属性
)
注意:不要修改源码,在自己的视图内部重写check_permission()方法,或者自定义视图类让其他视图继承,覆盖APIView的同名方法。