DRF之权限执行流程
1.源码分析
- 首先客户端所有的请求到来之后都会执行dispatch()方法,dispatch()方法会根据不同的请求方式,从而触发不同的方法,如GET/POST/PUT/DELETE/UPDATE等方法.
#先进入dispatch方法
class APIView(View):
...
def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
#这里对Django的request做了进一步的封装
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers
try:
# initial 处理版权信息,认证,权限,请求用户进行访问频率的限制
self.initial(request, *args, **kwargs)
#点击进入initial
↓
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) #这里做了用户权限设置
#点击进入check_permissions(request)
↓
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)
)
def check_object_permissions(self, request, obj):
#用户对象级别的权限
"""
Check if the request should be permitted for a given object.
Raises an appropriate exception if the request is not permitted.
"""
for permission in self.get_permissions():
if not permission.has_object_permission(request, self, obj):
self.permission_denied(
request, message=getattr(permission, 'message', None)
)
#点击进入get_permissions()
↓
def get_permissions(self):
#这里返回了一个权限的对象列表
return [permission() for permission in self.permission_classes]
↓
permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES #所以可以使用全局配置
#进入api_settings
↓
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES':['api.utils.permission.MyPermission',...]
} #全局默认使用 Mypermission 上面是 文件路径 不想用的就重写
#回到check_permission 方法
def check_permissions(self, request):
for permission in self.get_permissions():
if not permission.has_permission(request, self): #如果 has_permission返回false则权限不通过,否则通过
self.permission_denied(
request, message=getattr(permission, 'message', None)
) #message是提示错误的信息
↓
def permission_denied(self, request, message=None):
if request.authenticators and not request.successful_authenticator:
raise exceptions.NotAuthenticated() #报错
raise exceptions.PermissionDenied(detail=message)
2.代码实现
#新建permission.py文件
from rest_framework.authentication import BaseAuthentication, exceptions
from rest_framework.permissions import BasePermission
from app import models
class SVIPPermission(BasePremission): #需继承BasePermission
message = '级别不够,无法访问'
def has_permission(self, request, view): #重写这个方法 对应源码,返回false就是不通过
if request.user.user_type != 3:
return False
return True
class MyPermission(BasePremission):
def has_permission(self, request, view):
if request.user.user_type == 3:
return False
return True
#在view视图函数中
class OrderView(APIView):
'''
订单业务svip
'''
permission_classes = [SVIPPermission,] #自己写了用自己的
def get(self, request, *args, **kwargs):
ret = {'code': 1000, 'msg': None}
try:
ret['data'] = ORDER_DICT
except Exception as e:
pass
return JsonResponse(ret)
class UserInfoView(Base): #什么也没有写 默认是全局的权限设置类
'''
订单业务普通用户
'''
def get(self, *args, **kwargs):
return HttpResponse('用户信息')
3.全局配置
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES':['api.utils.permission.MyPermission',...]
} #全局默认使用 Mypermission 上面是 文件路径 不想用的就重写
4.代码规范
#和用户认证相同 权限类也都应该依据代码规范继承BasePermission
from rest_framework.permissions import BasePermission
class MyPermission(BasePermission):
pass
#BasePermission源码
class BasePermission(metaclass=BasePermissionMetaclass):
def has_permission(self, request, view):
return True
def has_object_permission(self, request, view, obj): #对某个对象是否有权限 力度更细
return True
5.has_object_permission
- 我们在写权限一般只用has_permission 但其实是有两个方法来控制权限的,另一个是has_object_permission,它的具体作用是:对某个对象是否有权限 粒度更细
- 分析:
#主要是在GenericAPIView中
GenericAPIView.get_object #只有调用这类的get_object这个方法 才必须有has_object_permission方法
check_object_permission
has_object_permission