Django Rest Framework 源码解析--权限
接上一篇文章;restframework重写的dispatch()方法中,执行了inital()函数。inital()中check_permissions(request) 方法实现了请求的鉴权、权限控制功能。
1、check_permissions(request)函数中,循环了权限类的对象列表,依次执行权限对象的 has_permission() 方法
如果有权限,则继续循环使用下一个权限对象再来检查request
如果没有权限,执行permission_denied()函数,抛出异常(通过权限对象的message变量来自定义异常信息
def check_permissions(self, request):
"""
Check if the request should be permitted.
Raises an appropriate exception if the request is not permitted.
检查请求是否被权限限制。
如果请求没有权限,抛出对应的异常
"""
for permission in self.get_permissions():
if not permission.has_permission(request, self):
self.permission_denied(
request, message=getattr(permission, 'message', None)
)
2、get_permissions()方法找到setting中指定的权限类,或者在View中重写的权限类
def get_permissions(self):
"""
Instantiates and returns the list of permissions that this view requires.
"""
# 列表推导式,来生成权限类的列表
return [permission() for permission in self.permission_classes]
3、如果没有权限,执行permission_denied()函数,抛出异常(通过权限对象的message变量来自定义异常信息)
def permission_denied(self, request, message=None):
"""
If request is not permitted, determine what kind of exception to raise.
"""
if request.authenticators and not request.successful_authenticator:
raise exceptions.NotAuthenticated()
# 抛出PermissionDenied(detail=message)异常,出入权限对象的message变量
raise exceptions.PermissionDenied(detail=message)
使用示例:
1、自定义的权限类继 承BasePermission 类
在重写 has_permission() 方法时,需要引入 request, view 参数,可以根据 request, view 来做权限控制
在重写 has_object_permission() 方法时, 需要引入 request, view, obj 参数,可以根据 request, view, obj 来做权限控制
@six.add_metaclass(BasePermissionMetaclass)
class BasePermission(object):
"""
A base class from which all permission classes should inherit.
"""
def has_permission(self, request, view):
"""
Return `True` if permission is granted, `False` otherwise.
"""
return True
def has_object_permission(self, request, view, obj):
"""
Return `True` if permission is granted, `False` otherwise.
"""
return True
自定义权限类,示例:
class MyPermission(BasePermission):
"""
自定义权限
"""
message = "无权访问!"
@classmethod
def get_permission_from_role(self, request):
try:
perms = request.user.roles.values(
'permissions__method',
).distinct()
return [p['permissions__method'] for p in perms]
except AttributeError:
return None
def has_permission(self, request, view):
perms = self.get_permission_from_role(request)
if perms:
if 'admin' in perms:
return True
elif not hasattr(view, 'perms_map'):
return True
else:
perms_map = view.perms_map
_method = request._request.method.lower()
for i in perms_map:
for method, alias in i.items():
if (_method == method or method == '*') and alias in perms:
return True
2、在View中重写permission_classes权限类列表,列表中几个权限类表示要经过几层权限检查(从左至右依次检查)
class TestView(APIView):
# 自定义方法权限映射
perms_map = ({'*': 'admin'}, {'*': 'test_all'}, {'post': 'test_copy'})
# 在View中重写permission_classes权限类列表,几个类表示要经过几层权限检查
permission_classes = (MyPermission,)
def post(self, request, format=None):
pass
3、或者在全局setting.py中指定权限类的路径,对全站的View进行默认的权限检查
REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES": ('restframework.permissions.MyPermission',)
}