数据库准备

image.png

构造token

正式场景使用jwt构造token,而不是这里这种方式。
用户访问接口:服务器生成一个token,用于保存到数据库和返回给用户。

  1. # models.py
  2. from django.db import models
  3. class UserInfo(models.Model):
  4. username = models.CharField(verbose_name="用户名", max_length=32)
  5. password = models.CharField(verbose_name="密码", max_length=64)
  6. token = models.CharField(verbose_name="TOKEN", max_length=64, null=True, blank=True)
  1. # views.py
  2. import uuid
  3. from rest_framework.views import APIView
  4. from rest_framework.response import Response
  5. from rest_framework.authentication import BaseAuthentication
  6. from rest_framework.exceptions import AuthenticationFailed
  7. # Create your views here.
  8. from app01 import models
  9. class AuthView(APIView):
  10. '''提交的数据 {"username": "mufeng", "password": "123456"}
  11. '''
  12. def post(self, request, *args, **kwargs):
  13. print(request.data)
  14. username = request.data.get('username')
  15. password = request.data.get('password')
  16. user_object = models.UserInfo.objects.filter(username=username, password=password).first()
  17. if not user_object:
  18. return Response({'code': 1000, 'data': '用户名或密码错误'})
  19. token = str(uuid.uuid4())
  20. user_object.token = token
  21. user_object.save()
  22. res = {'code': 0, 'data': {'token': token, 'name': username}}
  23. return Response(res)

访问接口
image.png
数据库的token字段成功保存。
image.png

认证类

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

认证类的内部就是去执行:authenticate方法,根据返回值来表示认证结果。

  • 抛出异常AuthenticationFailed,表示认证失败。内部还会执行 authenticate_header将返回值设置给响应头 WWW-Authenticate
  • 返回含有两个元素的元组,表示认证成功,并且会将元素的第1个元素赋值给 request.user、第2个值赋值给request.auth

    1. 1个值,一般是用户对象。
    2. 2个值,一般是token
  • 返回None,表示继续调用 后续的认证类 进行认证。 ```python from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed

class TokenAuthentication(BaseAuthentication): def authenticate(self, request): msg = {‘code’: 1002, ‘data’: ‘认证失败’} token = request.query_params.get(‘token’) if not token: raise AuthenticationFailed(msg)

  1. user_object = models.UserInfo.objects.filter(token=token).first()
  2. if not user_object:
  3. raise AuthenticationFailed(msg)
  4. return user_object, token
  1. ```python
  2. # 使用认证类
  3. class OrderView(APIView):
  4. authentication_classes = [TokenAuthentication]
  5. def get(self, request, *args, **kwargs):
  6. return Response({'code': 1000, 'data': '认证成功'})

image.png
image.png

返回None

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

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

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

  1. REST_FRAMEWORK = {
  2. "UNAUTHENTICATED_USER": lambda: None,
  3. "UNAUTHENTICATED_TOKEN": lambda: None,
  4. }

”返回None“的应用场景:

当某个API,已认证 和 未认证 的用户都可以方法时,比如:

  • 已认证用户,访问API返回该用户的视频播放记录列表。
  • 未认证用户,访问API返回最新的的视频列表。

注意:不同于之前的案例,之前案例是:必须认证成功后才能访问,而此案例则是已认证和未认证均可访问。

image-20210821214440034.png

多个认证类

一般情况下,编写一个认证类足矣。

当项目中可能存在多种认证方式时,就可以写多个认证类。例如,项目认证支持:

  • 在请求中传递token进行验证。
  • 请求携带cookie进行验证。
  • 请求携带jwt进行验证(后面讲述)。
  • 请求携带的加密的数据,需用特定算法解密(一般为app开发的接口都是有加密算法)

此时,就可以编写多个认证类,并按照需要应用在相应的视图中,例如:
image-20210821220439103.png

全局配置

在每个视图类的类变量 authentication_classes 中可以定义,其实在配置文件中也可以进行全局配置,例如

  1. REST_FRAMEWORK = {
  2. "UNAUTHENTICATED_USER": lambda: None,
  3. "UNAUTHENTICATED_TOKEN": lambda: None,
  4. "DEFAULT_AUTHENTICATION_CLASSES":["xxxx.xxxx.xx.类名","xxxx.xxxx.xx.类名",]
  5. }

底层源码实现

image-20210822092707803.png