今天我们来看看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