1.权限组件概述
在drf开发中,如果有些接口必须同时满足:A条件、B条件、C条件。 有些接口只需要满足:B条件、C条件,此时就可以利用权限组件来编写这些条件。
2.权限组件应用
默认情况下,须所有权限类中has_permission方法返回值均为True时,才能通过权限组件;这一点与认证组件不同。
2.1 编写权限类
from rest_framework.permissions import BasePermission
class UserPermission(BasePermission):
message = {"status": False, 'msg': "无权访问1"} # message使用详见源码分析部分,同时还是code。
def has_permission(self, request, view):
if request.user.role == 3:
return True
return False
class ManagerPermission(BasePermission):
message = {"status": False, 'msg': "无权访问2"}
def has_permission(self, request, view):
if request.user.role == 2:
return True
return False
class BossPermission(BasePermission):
message = {"status": False, 'msg': "无权访问2"}
def has_permission(self, request, view):
if request.user.role == 1:
return True
return False
2.2 在视图中进行应用
class UserView(NbApiView):
# 经理、总监、用户
permission_classes = [BossPermission, ManagerPermission, UserPermission]
def get(self, request):
print(request.user, request.auth)
return Response("UserView")
def post(self, request):
print(request.user, request.auth)
return Response("UserView")
3.权限组件源码分析
权限类参考第2.1 编写权限类部分内容
class APIView(View):
permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
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),
code=getattr(permission, 'code', None)
)
def get_permissions(self):
return [permission() for permission in self.permission_classes]
def permission_denied(self, request, message=None, code=None):
if request.authenticators and not request.successful_authenticator:
raise exceptions.NotAuthenticated()
raise exceptions.PermissionDenied(detail=message, code=code)
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)
# 核心代码-->2 执行check_permissions方法
self.check_permissions(request)
self.check_throttles(request)
def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
# 核心代码-->1
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
class UserView(APIView):
permission_classes = []
def get(self, request, *args, **kwargs):
return Response('user')
4.权限组件扩展
- 需求:将默认必须同时满足:A条件、B条件、C条件,修改为满足任意一个条件即可;
- 思路:本质上是修改
check_permissions方法; - 后续视图中集成以下代码中的
MyApiView类即可。
from rest_framework.views import APIView
class MyApiView(APIView):
def check_permissions(self, request):
no_permission_objects = []
for permission in self.get_permissions():
if permission.has_permission(request, self):
return
else:
no_permission_objects.append(permission)
else:
self.permission_denied(
request,
message=getattr(no_permission_objects[0], 'message', None),
code=getattr(no_permission_objects[0], 'code', None)
)