Django REST framework之认证组件实例以及源码流程分析

基于用户传入的token进行认证

需求:对于一些api需要用户登录成功之后才能访问,有些api又不需要登录就能访问

解决思路:   a:创建两张表

      b.用户来访问的时候带上服务器发给用户token值

1.创建models.py

 1 from django.db import models
 2 
 3 
 4 class UserInfo(models.Model):
 5     user_choices_type = (
 6         (1, '普通用户'),
 7         (2, 'vip用户'),
 8         (3, 'svip用户'),
 9     )
10     user_type = models.IntegerField(choices=user_choices_type)
11     username = models.CharField(max_length=32, unique=True)
12     password = models.CharField(max_length=64)
13 
14 
15 class UserToken(models.Model):
16     user = models.OneToOneField(to='UserInfo', on_delete=models.CASCADE)
17     token = models.CharField(max_length=64)

2.urls.py

1 urlpatterns = [
2     re_path('api/v1/auth/$', views.AuthView.as_view()),
3     re_path('api/v1/order/$', views.OrderView.as_view()),
4 ]

3.认证类

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 from rest_framework.authentication import BaseAuthentication
 5 from rest_framework.exceptions import AuthenticationFailed
 6 from api import models
 7 
 8 
 9 class Authticate(BaseAuthentication):
10 
11     def authenticate(self, request):
12         token = request._request.GET.get('token')
13         token_obj = models.UserToken.objects.filter(token=token).first()
14         if not token_obj:
15             raise AuthenticationFailed('用户认证失败')
16         return (token_obj.user, token_obj)
17 
18     def authenticate_header(self, request):
19         """
20         认证失败之后返回给浏览器响应头
21         :param request:
22         :return:
23         """
24         pass

4.views.py 

 1 from django.http import JsonResponse
 2 from rest_framework.views import APIView
 3 from api import models
 4 
 5 
 6 order_dict = {
 7     1: {
 8         'name': '拉皮条',
 9         'age': 18,
10         'gengder': '',
11         'content': '买了个充气的'
12     },
13     2: {
14         'name': '热狗',
15         'age': 18,
16         'gengder': '',
17         'content': '买了个非酋'
18     }
19 }
20 
21 
22 def md5(user):
23     import hashlib
24     import time
25     ctime = str(time.time())
26     m = hashlib.md5(user.encode('utf8'))
27     m.update(ctime.encode('utf8'))
28     return m.hexdigest()
29 
30 
31 class AuthView(APIView):
32     """
33     登录相关的逻辑
34     """
35     authentication_classes = []
36     def post(self, request, *args, **kwargs):
37 
38         ret = {'code': 1000, 'msg': None, 'token': None}
39         try:
40             user = request._request.POST.get('username')
41             pwd = request._request.POST.get('password')
42             obj = models.UserInfo.objects.filter(username=user, password=pwd).first()
43             if not obj:
44                 ret['code'] = 1001
45                 ret['msg'] = '用户名或者密码错误'
46             # 为登录用户创建token
47             token = md5(user)
48             models.UserToken.objects.update_or_create(user=obj, defaults={'token': token})
49             ret['token'] = token
50         except Exception as e:
51             ret['code'] = 1002
52             ret['msg'] = '请求异常'
53 
54         return JsonResponse(ret)
55 
56 
57 class OrderView(APIView):
58     """
59     订单相关业务
60     """
61 
62     def get(self, request, *args, **kwargs):
63         print(request.user, request.auth)
64         ret = {'code': 2000, 'msg': None, 'data': None}
65         try:
66             ret['data'] = order_dict
67         except Exception as e:
68             ret['code'] = 2001
69             ret['msg'] = '请求异常'
70         return JsonResponse(ret)

5.settings.py

1 REST_FRAMEWORK = {
2     'DEFAULT_AUTHENTICATION_CLASSES': ['api.utils.auth.Authticate', ],
3     # 'DEFAULT_AUTHENTICATION_CLASSES': [],  # AnonymousUser None配置文件中有
4     # 'UNAUTHENTICATED_USER': lambda: '匿名用户',
5     # 'UNAUTHENTICATED_USER': None,
6     # 'UNAUTHENTICATED_TOKEN': None,
7 }

总结:实现的思路就是每次用户登录的时候,需要带上token值,如果没有带就获取不到相应的资源,如果登录成功就给用户创建token值,并且给用户返回,若第二次用户登录就给用户更新,同时也返回给用户,当然用户没登录成功就给用户返回相关的错误信息。

认证组件的源码流程分析

 请求进来先找自己的dispatch方法,然而没有,就走父类的APIView,发现有dispatch方法 ,执行self.initialize_request方法,封装Request,之前还有解析器-->执行self.get_authenticators()-->[auth() for auth in self.authentication_classes]列表式生成一个个认证对象--->authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES默认去配置文件中,若自己有,执行initial(self, request, *args, **kwargs)方法---->执行self.perform_authentication(request)------>request.user这是个静态属性----->self._authenticate()---->_authenticate(self)---->authenticator.authenticate(self)---->返回必须是一个元组。

_authenticate(self):循环认证类的所有对象,执行认证类的authenticate方法,1.如果authenticate方法抛异常,执行self._not_authenticated()2.有返回值必须是元组(request.user,request.auth)3.如果返回None,进入下一个认证对象处理,如果全部都是None跳出循环,执行_not_authenticated(self)方法去配置文件了if api_settings.UNAUTHENTICATED_USER就是匿名用户AnonymousUser,否则是slef.user=None,self.auth = api_settings.UNAUTHENTICATED_TOKEN()为None否则self.auth=None。

内置认证类

BaseAuthentication

我们写认证类的时候,必须继承它实现authenticate方法不写直接抛错,authenticate_header这个方法是认证失败给用户返回的响应头信息401认证不通过,也是必须写的方法,但是一般不做什么处理。

BasicAuthentication

这个类大概是通过浏览器把用户的密码和用户名通过base64加密之后发给服务端。

SessionAuthentication

通过django的session做的认证。

TokenAuthentication

其实跟我哪个认证token差不多。

RemoteUserAuthentication

这个类是通过认证http请求头。

      

猜你喜欢

转载自www.cnblogs.com/Alexephor/p/11285272.html