• 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请求头。

          

  • 相关阅读:
    falsh读取网页数据
    IBATISNET中的lazyLoad
    Json.Net学习笔记(四) Json对象的读写
    Json.Net学习笔记(五) 自定义Json序列化特性
    Json.Net学习笔记(三) Json与Xml之间的转换
    将 GridView 中的内容导出到 Excel 中多个工作表(Sheet) 的方法
    jQuery–20个最新的jQuery效果.
    Json.Net学习笔记(七) 序列化集合
    Json.Net学习笔记(六) Json.Net中关于时间的序列化
    Json.Net 学习笔记(一)
  • 原文地址:https://www.cnblogs.com/Alexephor/p/11285272.html
Copyright © 2020-2023  润新知