APIView之dispatch中认证与权限源码刨析:

Posted Morpheus1024

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了APIView之dispatch中认证与权限源码刨析:相关的知识,希望对你有一定的参考价值。

权限和认证源码解析:

上回讲到dispatch的核心是认证与权限,现在我们来分析一下这两者之间的源码:

self.perform_authentication(request)
self.check_permissions(request)

执行认证:

def perform_authentication(self, request):
    """
    Perform authentication on the incoming request.

    Note that if you override this and simply \'pass\', then authentication
    will instead be performed lazily, the first time either
    `request.user` or `request.auth` is accessed.
    """
    request.user
# property可以将方法转换为属性
@property
def user(self):
    """
    Returns the user associated with the current request, as authenticated
    by the authentication classes provided to the request.
    """
    # 如果你没有user.
    if not hasattr(self, \'_user\'):
        with wrap_attributeerrors():
            self._authenticate()
    return self._user

@user.setter
def user(self, value):
    """
    Sets the user on the current request. This is necessary to maintain
    compatibility with django.contrib.auth where the user property is
    set in the login and logout functions.

    Note that we also set the user on Django\'s underlying `HttpRequest`
    instance, ensuring that it is available to any middleware in the stack.
    """
    self._user = value
    self._request.user = value
def _authenticate(self):
    """
    Attempt to authenticate the request using each authentication instance
    in turn.
    """
    #遍历认证器
    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()
将所有的认证器都遍历了一遍,然后调用每个认证器的认证方法,认证成功返回一个两位的元组,如果异常或为空都是认证失败。认证成功会将结果拆包存到self上面,即request。
class BaseAuthentication:
    """
    All authentication classes should extend BaseAuthentication.
    """
	# 抽象方法
    def authenticate(self, request):
        """
        Authenticate the request and return a two-tuple of (user, token).
        """
        # 必须重写,不重写就抛异常
        raise NotImplementedError(".authenticate() must be overridden.")

    def authenticate_header(self, request):
        """
        Return a string to be used as the value of the `WWW-Authenticate`
        header in a `401 Unauthenticated` response, or `None` if the
        authentication scheme should return `403 Permission Denied` responses.
        """
        pass

创建authentications.py >

class TokenAuthentication(BaseAuthentication):
    #  Authenticate the request and return a two-tuple of (user, token).
	def authenticate(self, request):
    	try:
            # 查询参数:querry_params  == 以前的 "GET"
            token = request.query_params.get("token")
            # 缓存中拿token
            user_id = cache.get(token)
            user = User.objects.get(pk=user_id) 
            # 认证成功
            return user,token
        
        except Exception as e:
            print(e)
            # 认证失败
            return 

view.py >

from 0.0 import TokenAuthentication

class UserView(GenericAPIView):
    # 获取结果集
    queryset = Cart.objects.all()
    # 将数据库序列化
    serializer_class = CartSerializer
    # 获取认证
    authentication_classes = TokenAuthentication,
    
    def get(self, request, *args, **kwargs):
        
        print(request.user) # 判断是不是我们库里的用户,游客用户是AnonymosUser
        
        data = {
            "msg": "登录成功",
        }
        
        return Response(data)

检查权限:

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),
                code=getattr(permission, \'code\', None)
            )

如果没有权限,权限被拒绝。

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.
        """
        # 如果授予权限,则返回“True”,否则返回“False”。
        return True

    def has_object_permission(self, request, view, obj):
        """
        Return `True` if permission is granted, `False` otherwise.
        """
        return True

创建 permissions.py >

from rest_framework.permissions import BasePermission
from App.models import User
class LoginPermission(BasePermission):

    def has_permission(self, request, view):
        # 只针对get请求
        if request.method == "GET":
        # request.user 是我们自己的User,拥有权限,其他就是没有权限
        return isinstance(request.user,User)
    return True

view.py >

class UserView(GenericAPIView):
    # 获取结果集
    queryset = Cart.objects.all()
    # 将数据库序列化
    serializer_class = CartSerializer
    # 获取认证
    authentication_classes = TokenAuthentication,
    # 获取权限
    permission_classes = LoginPermission,
    
    def get(self, request, *args, **kwargs):
        
        serializer = UserSerializser(request.user)
        
        data = {
            "msg": "登录成功",
            "data": serializer.data
        }
        
        return Response(data)
        
以上就是用最少的代码来验证用户的身份。

以上是关于APIView之dispatch中认证与权限源码刨析:的主要内容,如果未能解决你的问题,请参考以下文章

DjangoDRF源码分析之五大模块

DjangoRestFramework学习三之认证组件权限组件频率组件url注册器响应器分页组件

drf 权限认证

django rest_fremework源码之权限流程剖析

Django之REST_FRAMEWORK 认证组件

三大认证之认证组件和权限组件