05 DRF-权限

认证组件 = [认证类,认证类,...]  --> 执行每个认证类的authenticate方法:
                                    - 认证成功或失败,不会在执行后续的认证类
                                    - 返回None,执行后续的认证类
                                    - 像是 or 



权限组件 = [权限类,权限类,...]  --> 执行每个权限类的has_permission方法:
                                    - 认证True通过,False表示不通过
                                    - 执行所有的权限类
                                    - 像是 and
                                    - 学会源码流程后,也可以是 or
									
					默认情况下,保证所有的权限类中的has_permission方法都返回True

1 权限组件应用方式

权限组件应用时:可以局部使用,也可以全局使用。

per.py
import random
from rest_framework.permissions import BasePermission


class MyPermission(BasePermission):
    def has_permission(self, request, view):
        # 获取请求中的数据,校验
        v1 = random.randint(1, 3)
        if v1 == 2:
            return True
        return False
from ext.per import MyPermission

class OrderView(APIView):
    permission_classes = [MyPermission, ]  # 应用在单个视图类中

    def get(self, request):
        return Response('OrderView.')
REST_FRAMEWORK = {
    "UNAUTHENTICATED_USER": None,
    "DEFAULT_PERMISSION_CLASSES": [
        'ext.per.MyPermission',
    ]
}

2 多个权限类组件应用顺序

import random
from rest_framework.permissions import BasePermission


class MyPermission1(BasePermission):
    # 权限验证失败时,读取并返回message
    message = {'status': False, 'msg': '无权访问'}

    def has_permission(self, request, view):
        # 获取请求中的数据,校验
        v1 = random.randint(1, 3)
        if v1 == 2:
            return True
        return False


class MyPermission2(BasePermission):
    message = {'status': False, 'msg': '无权访问'}

    def has_permission(self, request, view):
        return False
    

class MyPermission3(BasePermission):
    message = {'status': False, 'msg': '无权访问'}

    def has_permission(self, request, view):
        return True
from ext.per import MyPermission1, MyPermission2, MyPermission3

class OrderView(APIView):
    permission_classes = [MyPermission1, MyPermission2, MyPermission3]

    def get(self, request):
        return Response({'status': True, 'data': [11, 22, 33]})

多个权限组件认证顺序:首先会按照列表中的顺序来,先认证MyPermission1后依次执行,成功往后执行,失败返回。
只有都成功,认证才会通过。有一个失败,则认证失败。


3 权限认证,错误返回数据

import random
from rest_framework.permissions import BasePermission


class MyPermission1(BasePermission):
    # 权限验证失败时,读取并返回message
    message = {'status': False, 'msg': '无权访问'}

    def has_permission(self, request, view):
        # 获取请求中的数据,校验
        v1 = random.randint(1, 3)
        if v1 == 2:
            return True
        return False

4 权限认证-扩展

权限认证组件默认条件:是所有的权限类都要通过后,方可通过。

那么我们如何自定义:通过一个权限类,就可以通过呢?

在自己的视图类中重写check_permissions方法:

class OrderView(APIView):
    permission_classes = [MyPermission1, ]

    def get(self, request):
        return Response({'status': True, 'data': [11, 22, 33]})

    def check_permissions(self, request):
        no_permission_obj = []
        for permission in self.get_permissions():
		    # 当第一个权限类通过,就立即返回
            if permission.has_permission(request, self):
                return
            else:
			# 没有通过的权限类加入no_permission_obj
                no_permission_obj.append(permission)
        else:
            self.permission_denied(
                request,
                message=getattr(no_permission_obj[0], 'message', None),
                code=getattr(no_permission_obj[0], 'code', None)
            )

5 源码分析

点击查看代码
class Request:
    def __init__(self, request, authenticators=None):
        self.authenticators = authenticators or ()

    @property
    def user(self):
        if not hasattr(self, '_user'):
            with wrap_attributeerrors():
                self._authenticate()
        return self._user

    @user.setter
    def user(self, value):
        self._user = value
        self._request.user = value

    def _authenticate(self):
        # 读取每个认证组件的对象,执行 authenticate 方法,self=request对象
        for authenticator in self.authenticators:
            try:
                user_auth_tuple = authenticator.authenticate(self)
            except exceptions.APIException:
                self._not_authenticated()
                raise

            if user_auth_tuple is not None:
                self._authenticator = authenticator
                self.user, self.auth = user_auth_tuple
                return

        self._not_authenticated()

    def _not_authenticated(self):  # 匿名访问
        self._authenticator = None

        if api_settings.UNAUTHENTICATED_USER:
            self.user = api_settings.UNAUTHENTICATED_USER()
        else:
            self.user = None

        if api_settings.UNAUTHENTICATED_TOKEN:
            self.auth = api_settings.UNAUTHENTICATED_TOKEN()
        else:
            self.auth = None


class APIView(View):
	permission_classes = api_settings.DEFAULT_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 get_permissions(self):
        return [permission() for permission in self.permission_classes]

    def check_permissions(self, request):
    	# 读取permission的对象列表
        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)
                )


        for permission in self.get_permissions():
            if permission.has_permission(request, self):
            	return
        else:
            self.permission_denied(
                request,
                message=getattr(permission, 'message', None),
                code=getattr(permission, 'code', None)
            )



    def initial(self, request, *args, **kwargs):
    	# 认证组件,循环执行每个authticate方法,失败抛出异常;request.user/auth
        self.perform_authentication(request)  
        # 权限组件,假设登录成功,request.user/auth 都有值
        self.check_permissions(request) 
        self.check_throttles(request)

    def dispatch(self, request, *args, **kwargs):
    self.args = args  # url传递的参数接收
    self.kwargs = kwargs  # url传递的参数接收

    # 第一步:请求的封装(django的request对象 + authenticators认证组件)—> 加载认证组件的过车用
    request = self.initialize_request(request, *args, **kwargs)
    self.request = request
    self.headers = self.default_response_headers  # deprecate?

    try:
        # 第二步:request
        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 OrderView(APIView):
    permission_classes = [MyPermission1, ]

    def get(self, request):
        return Response({'status': True, 'data': [11, 22, 33]})


6 小小应用

image

ext.view.py:

from rest_framework.views import APIView

class NbApiView(APIView):
    def check_permissions(self, request):
        no_permission_obj = []
        for permission in self.get_permissions():
            # 当第一个权限类通过,就立即返回
            if permission.has_permission(request, self):
                return
            else:
                # 没有通过的权限类加入no_permission_obj
                no_permission_obj.append(permission)
        else:
            self.permission_denied(
                request,
                message=getattr(no_permission_obj[0], 'message', None),
                code=getattr(no_permission_obj[0], 'code', None)
            )
posted @ 2022-10-18 14:06  角角边  Views(28)  Comments(0)    收藏  举报