认证和权限
一、认证
在开发后端的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 modelsclass TokenAuthentication(BaseAuthentication):def authenticate(self, request):# 返回一个none,等一跳过当前认证类,继续执行下一个认证类# return Nonetoken = request.query_params.get('token')if not token:# 3.返回Nonereturn Noneuser_object = models.UserInfo.objects.filter(token=token).first()if not user_object:# 1.返回报错信息raise AuthenticationFailed({"code": 1002, "data": "认证失败"})# 2.返回的值放哪里了,两个值分别负值给了这两个值# request.user# request.authreturn user_object, tokendef 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) # 获取认证类返回的tokenif 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) # 获取认证类返回的tokenif 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,不满足返回falsedef 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 Trueelse:# 只要使用了choice,拿到数字对应的中文# get_字段名_display()user_type=request.user.get_user_type_display()self.message=f'您是:{user_type},您没有权限访问'return Falseelse: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]}})