一、权限组件的使用
# 用户信息表 class UserInfo(models.Model): name = models.CharField(max_length=32) # 写choice user_choice=((0,'普通用户'),(1,'会员'),(2,'超级用户')) # 指定choice,可以快速的通过数字,取出文字 user_type=models.IntegerField(choices=user_choice,default=0) pwd = models.CharField(max_length=32) # 用户token class UserToken(models.Model): token = models.CharField(max_length=64) user = models.OneToOneField(to=UserInfo)
1、使用语法
from rest_framework.permissions import BasePermission # 写一个权限类 class UserPermission(BasePermission): # 重写没有权限时的数据 message = '您没有权限' # 重写has_permission()方法,传入三个参数 # 第一个是对象自身(自动传);第二个是request对象;第三个是 def has_permission(self, request, view): # 只要认证通过,就会把当前用户对象放到request中 user_type = request.user.user_type # get_字段名_display() 可以获取choice数字对应的具体值 # user_type_name = request.user.get_user_type_display() # print(user_type_name) if user_type == 2: return True return Fals
class Book(APIView): # 用户认证 authentication_classes = [UserAuth.UserAuth, ] # 权限判断 permission_classes = [MyPerm.UserPermission, ] def get(self, request, *args, **kwargs): response = {'status': 100, 'msg': '查询成功'} ret = models.Book.objects.all() ser = MySerializer.BookSerializer(instance=ret, many=True) response['data'] = ser.data return JsonResponse(response, safe=False)
2、全局使用、局部使用、局部禁用权限
(1)全局使用
- 在settings文件中配置,配置完以后,就无需在视图类中写,已经是所有视图类都需要权限判断
- 必须为
REST_FRAMEWORK
,key值必须为DEFAULT_AUTHENTICATION_CLASSES
REST_FRAMEWORK={ 'DEFAULT_PERMISSION_CLASSES':['app01.MyPerm.UserPermission',], }
(2)局部使用
在需要使用的视图类中写,只对当前视图类起认证作用,重新定义permission_classes
class Book(APIView): # # 该方法是局部使用认证 authentication_classes = [UserAuth.UserAuth, ] # 该方法是局部使用权限 permission_classes = [MyPerm.UserPermission, ] def get(self, request, *args, **kwargs): response = {'status': 100, 'msg': '查询成功'} ret = models.Book.objects.all() ser = MySerializer.BookSerializer(instance=ret, many=True) response['data'] = ser.data return JsonResponse(response, safe=False)
(3)局部禁用
在配置过全局权限判断以后,有些视图类不需要判断权限,可以局部禁用权限证,只需将permission_classes
定义为空列表即可。
class Book(APIView): # # 该方法是局部使用认证 authentication_classes = [UserAuth.UserAuth, ] # 该方法是局部禁用权限 permission_classes = [] def get(self, request, *args, **kwargs): response = {'status': 100, 'msg': '查询成功'} ret = models.Book.objects.all() ser = MySerializer.BookSerializer(instance=ret, many=True) response['data'] = ser.data return JsonResponse(response, safe=False)
二、源码分析
as_view ----------> view -------------> dispatch -------> Request包装新的request ------> 认证、权限、频率 --------> 根据请求方式分发到不同的方法
1、Book中没有as_view
2、APIView的as_view
class APIView(View): @classmethod # cls 是 Book类 def as_view(cls, **initkwargs): # view = super(APIView, Book).as_view(**initkwargs) view = super(APIView, cls).as_view(**initkwargs) view.cls = cls view.initkwargs = initkwargs # Note: session based authentication is explicitly CSRF validated, # all other authentication is CSRF exempt. return csrf_exempt(view)
3、view = super(APIView, cls).as_view(**initkwargs) ---------------------> View中的as_view
class View(object): @classonlymethod # cls====> Book def as_view(cls, **initkwargs): def view(request, *args, **kwargs): # 实例化产生一个book对象 self = cls(**initkwargs) if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request self.args = args self.kwargs = kwargs # 调dispatch方法 return self.dispatch(request, *args, **kwargs) view.view_class = cls view.view_initkwargs = initkwargs # take name and docstring from class update_wrapper(view, cls, updated=()) # and possible attributes set by decorators # like csrf_exempt from dispatch update_wrapper(view, cls.dispatch, assigned=()) return view
4、return self.dispatch(request, *args, **kwargs) ----------------> dispatch
self====> Book对象,一层层找dispatch
APIView中找到dispatch
class APIView(View): def dispatch(self, request, *args, **kwargs): self.args = args self.kwargs = kwargs # (a)初始化request,就是通过Request类来包装原生request,得到包装后的request request = self.initialize_request(request, *args, **kwargs) # 从现在开始request就是包装后的request self.request = request self.headers = self.default_response_headers # deprecate? try: # (b) 认证、权限、频率 self.initial(request, *args, **kwargs) # Get the appropriate handler method # http_method_names表示列表['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] 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
(a)request = self.initialize_request(request, *args, **kwargs) 包装 request
self 是Book对象
class APIView(View): # 默认的认证列表类 authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. """ parser_context = self.get_parser_context(request) # (a-b)实例化初始化产生新的request对象 return Request( request, parsers=self.get_parsers(), authenticators=self.get_authenticators(), # 认证类实例化产生的对象的列表 negotiator=self.get_content_negotiator(), parser_context=parser_context )
def get_authenticators(self): """ Instantiates and returns the list of authenticators that this view can use. """ return [auth() for auth in self.authentication_classes]
(a------1)return Request( ··· ) ----------> Request类初始化
def __init__(self, request, parsers=None, authenticators=None, negotiator=None, parser_context=None): assert isinstance(request, HttpRequest), ( 'The `request` argument must be an instance of ' '`django.http.HttpRequest`, not `{}.{}`.' .format(request.__class__.__module__, request.__class__.__name__) ) self._request = request self.parsers = parsers or () self.authenticators = authenticators or () self.negotiator = negotiator or self._default_negotiator() self.parser_context = parser_context self._data = Empty self._files = Empty self._full_data = Empty self._content_type = Empty self._stream = Empty if self.parser_context is None: self.parser_context = {} self.parser_context['request'] = self self.parser_context['encoding'] = request.encoding or settings.DEFAULT_CHARSET force_user = getattr(request, '_force_auth_user', None) force_token = getattr(request, '_force_auth_token', None) if force_user is not None or force_token is not None: forced_auth = ForcedAuthentication(force_user, force_token) self.authenticators = (forced_auth,)
(b)self.initial(request, *args, **kwargs) -----> 认证、权限、频率
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 # (b------1) 认证 self.perform_authentication(request) # (b------2)权限 self.check_permissions(request) # 频率 self.check_throttles(request)
(b------1) self.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. """ # (b------1---------1) get_permissions 权限类对象组成的列表 for permission in self.get_permissions(): # 重写的就是这个has_permission()方法,判断当前用户是否有权限 if not permission.has_permission(request, self): self.permission_denied( request, message=getattr(permission, 'message', None) )
(b------1---------1) self.get_permissions() -------> 获取权限类对象组成的列表
def get_permissions(self): """ Instantiates and returns the list of permissions that this view requires. """ return [permission() for permission in self.permission_classes]
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Django框架(二十)– Django rest_framework-权限组件 - Python技术站