权限源码流程
2020-07-21 本文已影响0人
小吉头
权限模块
rest_framework.permissions
是restframework提供的权限模块,其他权限类都要继承BasePermission
类
权限验证流程
在dispatch()
方法中,有下面两段关键代码:
...
#封装Request对象
request = self.initialize_request(request, *args, **kwargs)
...
#认证、权限、限流验证
self.initial(request, *args, **kwargs)
...
在initial()
方法中进行了认证、权限、限流验证:
def initial(self, request, *args, **kwargs):
"""
Runs anything that needs to occur prior to calling the method handler.
"""
self.format_kwarg = self.get_format_suffix(**kwargs)
# Perform content negotiation and store the accepted info on the request
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg
# Determine the API version, if versioning is in use.
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme
# Ensure that the incoming request is permitted
self.perform_authentication(request) #认证
self.check_permissions(request) #权限
self.check_throttles(request) #限流
下面看下权限的流程
class APIView(View):
...
permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES#跟认证流程类似,如果在settings.py中定义了`DEFAULT_PERMISSION_CLASSES`会覆盖restframework settings.py中的定义
...
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()
raise exceptions.PermissionDenied(detail=message)
def get_permissions(self):
"""
Instantiates and returns the list of permissions that this view requires.
"""
return [permission() for permission in self.permission_classes]
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)
)
本例settings.py定义:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES':[
'rest_framework.permissions.IsAuthenticated',
'rest_framework.permissions.IsAdminUser'
]
}
所以for permission in self.get_permissions():
中的self.get_permissions()
就是[IsAuthenticated(),IsAdminUser()]
遍历list中对象,调用has_permission(request, self)
进行认证,self指向封装的Request对象。返回False,权限认证失败。可以定义message属性实现权限验证失败自定义提示。
以IsAuthenticated
类为例,查看源码:
class BasePermission(metaclass=BasePermissionMetaclass):
"""
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):#RetrieveModelMixin获取单个对象,self.get_object()实际调用的是GenericAPIView中的get_object(),里面的self.check_object_permissions(self.request, obj)会检测是否有操作该对象的权限
"""
Return `True` if permission is granted, `False` otherwise.
"""
return True
#认证通过才返回True
class IsAuthenticated(BasePermission):
"""
Allows access only to authenticated users.
"""
def has_permission(self, request, view):
return bool(request.user and request.user.is_authenticated)
自定义权限类
根据验证认证的规则,自定义认证类,继承自BasePermission
utils目录下新建permission.py
from rest_framework.permissions import BasePermission
class MyPermission(BasePermission):
message = "用户没有访问权限"#自定义权限认证失败提示
def has_permission(self, request, view):
if request.user == "xiaobai":
return True
return False
全局配置
如果想让所有视图都必须要认证后才能访问,可以在django项目的settings.py中设置REST_FRAMEWORK
变量,即本篇开始时写的,修改成自定义的认证类:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES':['utils.permission.MyPermission']
}
局部配置
如果只是某个视图使用,可以在类中定义属性,比如:permission_classes = [MyPermission]
。
如果不需要认证,可以写成permission_classes = []