三、django rest_framework源码之权限流程剖析
1 绪言
上一篇中分析了认证部分的源码,认证后的下一个环节就是权限判定了。事实上,权限判定肯定要与认证联合使用才行,因为认证部分不会对请求进行禁止或者是允许,而只是根据请求中用户信息进行用户身份判断,而权限判定就是认证中添加的用户身份进行权限判定。权限判定的入口在dispatch方法中调用的initial方法中,如下所示:
def initial(self, request, *args, **kwargs): …… # Ensure that the incoming request is permitted self.perform_authentication(request) #认证 self.check_permissions(request) #权限判定 self.check_throttles(request)
2 源码分析
当执行check_permissions方法的时候,权限判定也就开始了,贴出check_permissions方法的源码:
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) ) #有权限的话继续下一个权限类实例,直到遍历完所有实例
check_permissions方法首先遍历权限类实例列表,这个列表从哪来呢?我们看看get_permissions方法就知道了:
def get_permissions(self): return [permission() for permission in self.permission_classes]
这两行代码有没有很眼熟?没错,在上一篇认证源码分析中也有一个列表生成式生成所有配置好的权限类实例,连读取权限类的方式都是一样的,与权限类不同的是,认证类的这个环境放在加工处理request请求的方法中,然后将所有认证类实例封装进了request中。当然,这跟权限类没关系,我们现在只需要知道这个方法会读取配置的权限类,然后依次实例化并返回列表。但值得注意的是,里面有一个message属性,是指拒绝访问之后返回的提示信息,自定义权限类的时候可以指定message的值。
在for循环中,不断遍历权限实例对象,执行它的has_permission方法,我们以djangorestfromework自带的AllowAny为例进行分析
class AllowAny(BasePermission): def has_permission(self, request, view): return True
AllowAny类的has_permission方法直接就返回一个True,因为AllowAny这个类的功能就是允许所有访问,也就是说在has_permission类中,如果允许访问,就返回True,拒绝访问就返回False。
权限实例对象列表中可能有多个权限类实例,只要有一个返回的是False,抛出异常,那么就拒绝访问。这个异常是就是在permission_denied方法中抛出的,这个方法会在has_permission方法返回False时执行,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)
如有所有权限类都遍历完了,都返回True,那么权限判定这个环节就结束了。
3 自定义权限类
自定义的权限类必须实现has_permission方法,另外可以在类中指定拒绝访问时的message,当然这不是必须的。以下是自定义的一个权限类,功能是只允许用户名为“admin”的用户访问,
拒绝其他所有用户,拒绝是提示“您不是admin用户,无权访问”:
from rest_framework.permissions import BasePermission class MyAdminPermission(BasePermission): message = '您不是admin用户,无权访问' def has_permission(self, request, view): if request.user == "admin": return True
4 配置权限类
配置权限类的方法和配置认证类差不多:
局部配置:
在视图类中加入以下代码:
DEFAULT_PERMISSION_CLASSES = [MyAdminPermission,]
注意:别忘了逗号。
全局配置:
在项目的settings.py文件中加入:
REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': [ 'myapp.util.permission. MyAdminPermission ', ] }
作者:奥辰
微信号:chb1137796095
Github:https://github.com/ChenHuabin321
欢迎加V交流,共同学习,共同进步!
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。