04认证和权限

认证和权限

一、认证

在开发后端的API时,不同的功能会有不同的限制,例如:

  • 无需认证,就可以访问并获取数据。
  • 需认证,用户需先登录,后续发送请求需携带登录时发放的凭证

在drf中也给我们提供了 认证组件 ,帮助我们快速实现认证相关的功能

【1】认证组件使用步骤

(1)创建认证组件类
# 引入相关模块
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed

# 创建认证类
class TokenAuthentication(BaseAuthentication):
    def authenticate(self, request):
      	# 认证逻辑处理
        # 返回结果

    def authenticate_header(self, request):
        pass

(2)调用认证类
class OrderView(APIView):
  	# 引用认证类
    authentication_classes = [auth.TokenAuthentication, ]

    def get(self, request, *args, **kwargs):
        pass

【2】案例讲解

认证获取token,如果有token展示一个数据,没有token显示另外的数据

  • 创建认证类
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from app01 import models


class TokenAuthentication(BaseAuthentication):
    def authenticate(self, request):

        # 返回一个none,等一跳过当前认证类,继续执行下一个认证类
        # return None
        token = request.query_params.get('token')
        if not token:
            # 3.返回None
            return None
        user_object = models.UserInfo.objects.filter(token=token).first()
        if not user_object:
            # 1.返回报错信息
            raise AuthenticationFailed({"code": 1002, "data": "认证失败"})

        # 2.返回的值放哪里了,两个值分别负值给了这两个值
        # request.user
        # request.auth
        return user_object, token

    def authenticate_header(self, request):
        pass

(1)创建认证组件类TokenAuthentication,需要继承BaseAuthentication,这是固定格式

(2)认证类可以返回三个数据,根据不同需求看返什么

(3)第一个是返回报错信息raise AuthenticationFailed()固定格式,括号内填写错误信息

(4)第二个是返回含有两个元素的元组,表示认证成功,并且会将元素的第1个元素赋值给 request.user、第2个值赋值给request.auth ,此案例返回的事用户对象和token

第1个值,一般是用户对象。
第2个值,一般是token

(5)第三个return None,返回一个none,表示继续调用 后续的认证类 进行认证,返回两个None,表示request.user和request.auth都是None,表示匿名用户AnonymousUser

  • 调用认证类
# 我的订单接口
class OrderView(APIView):
    authentication_classes = [auth.TokenAuthentication, ]

    def get(self, request, *args, **kwargs):
        print(request.user)  # 获取认证类返回的用户对象
        print(request.auth)  # 获取认证类返回的token
        if not request.user:
            return Response({"code": 0, "data": [4, 5, 6]})
        return Response({"code": 0, "data": [1, 2, 3]})

(1)在视图类中设置类变量 authentication_classes的值为 认证类 auth.TokenAuthentication,,表示此视图在执行内部功能之前需要先经过 认证

(2)获取认证类返回的用户对象和token。根据数据进行相对应的操作,当用户没有认证时,request.user是None表示匿名用户显示return Response({"code": 0, "data": [4, 5, 6]}),如果通过认证显示return Response({"code": 0, "data": [1, 2, 3]})

(3)authentication_classes的值是个列表,可以放入多个认证类

【3】关于返回None

在视图类的 authentication_classes 中定义认证类时,传入的是一个列表,支持定义多个认证类。

当出现多个认证类时,drf内部会按照列表的顺序,逐一执行认证类的 authenticate 方法,如果 返回元组 或 抛出异常 则会终止后续认证类的执行;如果返回None,则意味着继续执行后续的认证类。

如果所有的认证类authenticate都返回了None,则默认 request.user="AnonymousUser" 和 request.auth=None,也可以通过修改配置文件来修改默认值。

REST_FRAMEWORK = {
 "UNAUTHENTICATED_USER": lambda: None,
 "UNAUTHENTICATED_TOKEN": lambda: None,
}

【4】多个认证类

  • 多个认证类时,如果在最后一个认证类时还未认证通过直接raise AuthenticationFailed抛出异常,不要在返回None了
  • 多个认证类时,前一个认证通过后,后续的认证类不会在执行
  • 如若前一个认证类未通过认证,但是选择抛出了AuthenticationFailed,这样的话,后续认证类也不会在执行

【5】全局配置认证组件

  • 如果每个类都需要使用认证组件,可以在settings配置文件里配置全局认证
  • 配置完全局认证组件后,视图类中则不需要在单独引用认证组件
REST_FRAMEWORK = {
    "UNAUTHENTICATED_USER": lambda: None,
    "UNAUTHENTICATED_TOKEN": lambda: None,
    # 全局配置认证组件,默认每个视图类都会执行这个认证组件
    #  "DEFAULT_AUTHENTICATION_CLASSES": ["app名称.认证组件的py文件.认证组件类名",]
    "DEFAULT_AUTHENTICATION_CLASSES": ["app01.auth.TokenAuthentication",]
}
  • 如果说某个视图类想单独使用某个认证组件
  • 在视图类下单独声明一个空的authentication_classes则可以覆盖全局默认的认证组件
class OrderView(APIView):
    authentication_classes = []

    def get(self, request, *args, **kwargs):
        print(request.user)  # 获取认证类返回的用户对象
        print(request.auth)  # 获取认证类返回的token
        if not request.user:
            return Response({"code": 0, "data": [4, 5, 6]})
        return Response({"code": 0, "data": [1, 2, 3]})

【6】认证组件的源码分析

二、权限

权限,读取认证中获取的用户信息,判断当前用户是否有权限访问,例如:普通用户、管理员、超级用户,不同用户具有不同的权限。

【1】权限组件使用步骤

(1)创建权限组件
# 引入权限组件模块
from rest_framework.permissions import BasePermission

# 创建权限组件类
class PermissionA(BasePermission):

    def has_permission(self, request, view):
      	# 固定的方法名,在里面处理权限的逻辑
        # 满足返回true,不满足返回false
      
    def has_object_permission(self, request, view, obj):
        pass

(2)调用权限类
# 视图类
class OrderView(APIView):
   
    # 此处声明permission_classes的值等于权限类名
    permission_classes = [auth.PermissionA, ]

    def get(self, request, *args, **kwargs):
        pass

【2】案例讲解

认证通过后,校验权限,权限通过才可看到数据,只有超级用户才能访问,其它用户都没有权限

  • 创建权限类
# 引入权限组件模块
from rest_framework.permissions import BasePermission

# 创建权限类,继承 BasePermission
class UserPermission(BasePermission):
  	# 重写has_permission方法
    def has_permission(self, request, view):
        # 判断权限,如果有权限,返回True,如果没有权限返回False
        # 获取当前登录用户---》request.user中拿到--》通过了认证
        print(type(request.user))
        # 判断用户是否登陆经并且经过了认证
        if request.user.is_authenticated :
            if request.user.user_type == 3:
                return True
            else:
                # 只要使用了choice,拿到数字对应的中文
                # get_字段名_display()
                user_type=request.user.get_user_type_display()
                self.message=f'您是:{user_type},您没有权限访问'
                return False
        else:
            self.message = '您还没登录呢'
            return False

  • 调用权限类
class OrderView(APIView):
    authentication_classes = [auth.TokenAuthentication, ]
    # 声明权限permission_classes的值是PermissionA类
    permission_classes = [auth.PermissionA, ]

【3】多个权限类

  • 当一个视图类有多个权限类时,必须所有权限类都通过才可往下执行

  • 当开发过程中需要用户同时具备多个权限(缺一不可)时,可以用多个权限类来实现。

    权限组件内部处理机制:按照列表的顺序逐一执行 has_permission 方法,如果返回True,则继续执行后续的权限类;如果返回None或False,则抛出权限异常并停止后续权限类的执行。

【4】全局配置权限组件

  • 如果每个类都需要使用认证组件,可以在settings配置文件里配置全局认证
  • 配置完全局认证组件后,视图类中则不需要在单独引用认证组件
REST_FRAMEWORK = {
  	# 全局权限组件,默认每个视图类都会执行这个权限组件
    #  "DEFAULT_PERMISSION_CLASSES": ["app名称.认证组件的py文件.认证组件类名",]
    "DEFAULT_PERMISSION_CLASSES":["app01.permission.PermissionA","app01.permission.PermissionB",]
}
  • 如果说某个视图类想单独使用某个认证组件或者不想使用权限组件
  • 在视图类下单独声明一个空的authentication_classes则可以覆盖全局默认的权限组件
class OrderView(APIView):
    authentication_classes = [auth.TokenAuthentication, ]
    # 声明一个空的permission_classes值,可以覆盖全局默认的权限
    permission_classes = []

    def get(self, request, *args, **kwargs):
        return Response({"code": 0, "data": {"user": None, "data": [1, 2, 3]}})

【5】权限源码分析

posted @ 2024-05-15 16:50  Formerly0^0  阅读(25)  评论(0)    收藏  举报