首页 > 其他分享 >【DRF-04】rest-framework之认证

【DRF-04】rest-framework之认证

时间:2024-05-23 21:07:31浏览次数:28  
标签:authenticate 04 self request rest framework token user def

  • 1.认证基本使用
    • 1.1:问题:有些API(订单信息)需要用户登录成功之后,才能访问;有些无需登录就能访问。
    • 1.2:解决思路:用户登录后,生成token--保存在数据库中,前端带token,允许访问,不带token,不允许访问。
    • 1.3:models
from django.db import models

class UserInfo(models.Model):
    user_type_choices = (
        (1,'普通用户'),
        (2,'VIP'),
        (3,'SVIP'),
    )
    user_type = models.IntegerField(choices=user_type_choices)
    username = models.CharField(max_length=32,unique=True)
    password = models.CharField(max_length=64)

class UserToken(models.Model):
    user = models.OneToOneField(to='UserInfo',on_delete=models.CASCADE)
    token = models.CharField(max_length=64)
  • 1.4:用户登录并且生成token,自定义认证类
from app01 import models
from rest_framework import exceptions
from django.http import JsonResponse
from rest_framework.authentication import BasicAuthentication
from django.shortcuts import HttpResponse

def md5(user):
    import hashlib
    import time
    ctime = str(time.time())
    m = hashlib.md5(bytes(user,encoding='utf-8'))
    m.update(bytes(ctime,encoding='utf-8'))
    return m.hexdigest()

class AuthView(APIView):
    """
    用于用户登录认证
    """
    def post(self,request,*args,**kwargs):
        self.dispatch()
        ret = {'code':1000,'msg':None}
        try:
            user = request._request.POST.get('username')
            pwd = request._request.POST.get('password')
            obj = models.UserInfo.objects.filter(username=user,password=pwd).first()
            if not obj:
                ret['code'] = 1001
                ret['msg'] = "用户名或密码错误"
            # 为登录用户创建token
            token = md5(user)
            # 存在就更新,不存在就创建
            models.UserToken.objects.update_or_create(user=obj,defaults={'token':token})
            ret['token'] = token
        except Exception as e:
            ret['code'] = 1002
            ret['msg'] = '请求异常'

        return JsonResponse(ret)

class Authtication(BasicAuthentication):
    def authenticate(self, request):
        token = request._request.GET.get('token')
        token_obj = models.UserToken.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationFailed("用户认证失败")

        # 在rest framework内部会将整个两个字段赋值给request,以供后续操作使用
        return (token_obj.user,token_obj)

    def authenticate_header(self, request):
        pass

class OrderView(APIView):
    # 模拟数据库订单数据
    ORDER_DICT = {
        1:{"name":"电脑","price":12340,"pcs":2},
        2:{"name":"手机","price":1999,"pcs":1}
    }

    authentication_classes = [Authtication,]     # 局部使用

    def get(self,request,*args,**kwargs):
        # request.user   #authenticate 返回的第一个元素
        # request.auth   #authenticate 返回的第二个元素
        ret = {'code':1000,'msg':None,'data':None}
        try:
            ret['data'] = self.ORDER_DICT
        except Exception as e:
            pass

        #son_dumps_params={"ensure_ascii":False} 解决使用JsonResponse返回显示中文
        return JsonResponse(ret,json_dumps_params={"ensure_ascii":False})

  • 1.5:效果展示

  • 2.内置认证类,一般我们自定义的认证类需要继承:BaseAuthentication

  • 3.全局使用

    • 3.1:上述1中是将自定义认证类,局部使用。
    • 3.2:全局使用,注意:认证类不能放到视图中,需要单独放置
    • 3.3:setting
REST_FRAMEWORK = {
    # 全局使用的认证类
    "DEFAULT_AUTHENTICATION_CLASSES":['app01.utils.auth.FirstAuthtication','app01.utils.auth.Authtication', ],
    # "DEFAULT_AUTHENTICATION_CLASSES":['app01.utils.auth.FirstAuthtication', ],
    # "UNAUTHENTICATED_USER":lambda :"匿名用户"
    "UNAUTHENTICATED_USER":None, # 匿名,request.user = None
    "UNAUTHENTICATED_TOKEN":None,# 匿名,request.auth = None
    }
  • 3.4:utils/auth.py
from rest_framework import exceptions
from app01 import models
from rest_framework.authentication import BaseAuthentication

class FirstAuthtication(BaseAuthentication):
    def authenticate(self,request):
        pass

    def authenticate_header(self, request):
        pass

class Authtication(BaseAuthentication):
    def authenticate(self,request):
        token = request._request.GET.get('token')
        token_obj = models.UserToken.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationFailed('用户认证失败')
        # 在rest framework内部会将整个两个字段赋值给request,以供后续操作使用
        return (token_obj.user, token_obj)

    def authenticate_header(self, request):
        return 'Basic realm="api"'
  • 3.5:如果某个API不需要使用认证,重写authentication_classes 置为空即可
class AuthView(APIView):
    authentication_classes = [ ]
    def post(self,request,*args,**kwargs):
       pass
  • 4.源码流程(重点)
    • 4.1:首先请求进来,走APIView的dispath,对request进行了封装initialize_request;
def dispatch(self, request, *args, **kwargs):
    """
    `.dispatch()` is pretty much the same as Django's regular dispatch,
    but with extra hooks for startup, finalize, and exception handling.
    """
    self.args = args
    self.kwargs = kwargs
    # 对原生的request进行加工(丰富了一些功能)
    # Request(request,parsers=self.get_parsers(),authenticators=self.get_authenticators(),
    #          negotiator=self.get_content_negotiator(),parser_context=parser_context)

    # request(原生的request,MyAuthentication对象)
    # 获取原生request:request._request
    # 获取认证类的对象:request.BasicAuthentication
    # 1.封装request
    request = self.initialize_request(request, *args, **kwargs)
    self.request = request
    self.headers = self.default_response_headers  # deprecate?

    try:
        # 2.认证
        self.initial(request, *args, **kwargs)

        # Get the appropriate handler method
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(),
                              self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed

        response = handler(request, *args, **kwargs)

    except Exception as exc:
        response = self.handle_exception(exc)

    self.response = self.finalize_response(request, response, *args, **kwargs)
    return self.response
  • 4.2:initialize_request方法
def initialize_request(self, request, *args, **kwargs):
    """
    Returns the initial request object.
    """
    parser_context = self.get_parser_context(request)

    return Request(
        request,
        parsers=self.get_parsers(),
        authenticators=self.get_authenticators(), #  [Foo(),Bar()]
        negotiator=self.get_content_negotiator(),
        parser_context=parser_context
    )
  • 4.3:get_authenticators方法,authentication_classes如果自己有就取自己的,没有就取配置文件
def get_authenticators(self):
    """
    Instantiates and returns the list of authenticators that this view can use.
    """
    # self.authentication_classes = [Foo,Bar]
    return [auth() for auth in self.authentication_classes]

class APIView(View):
    # The following policies may be set at either globally, or per-view.
    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
    pass
  • 4.4:initial方法,如果正常就反射执行对应的get/post方法,如果错误,抛出异常。
 def initial(self, request, *args, **kwargs):
      """
      Runs anything that needs to occur prior to calling the method handler.
      """
      self.format_kwarg = self.get_format_suffix(**kwargs)

      # Perform content negotiation and store the accepted info on the request
      neg = self.perform_content_negotiation(request)
      request.accepted_renderer, request.accepted_media_type = neg

      # Determine the API version, if versioning is in use.
      version, scheme = self.determine_version(request, *args, **kwargs)
      request.version, request.versioning_scheme = version, scheme

      # Ensure that the incoming request is permitted
      # 4.实现认证,权限,频率
      self.perform_authentication(request)
      self.check_permissions(request)
      self.check_throttles(request)
  • 4.5:perform_authentication方法
 def perform_authentication(self, request):
    """
    Perform authentication on the incoming request.

    Note that if you override this and simply 'pass', then authentication
    will instead be performed lazily, the first time either
    `request.user` or `request.auth` is accessed.
    """
    request.user
  • 4.6:执行request中的user方法
@property
def user(self):
    """
    Returns the user associated with the current request, as authenticated
    by the authentication classes provided to the request.
    """
    if not hasattr(self, '_user'):
        with wrap_attributeerrors():
            # 获取认证对象,进行一步一步的认证
            self._authenticate()
    return self._user
  • 4.6:执行_authenticate方法
def _authenticate(self):
    """
    Attempt to authenticate the request using each authentication instance
    in turn.
    """
    # [BasicAuthentication对象,]
    for authenticator in self.authenticators:
        try:
            # 执行认证类的authenticate方法
            # 1.如果authenticate方法抛出异常,self._not_authenticated()执行
            # 2.如果authenticate方法正常,如果有返回值,必须是元祖。self.user, self.auth = user_auth_tuple
            # 3.没报错,也没返回值,返回None。当前这个认证不处理,交给下一个认证处理
            user_auth_tuple = authenticator.authenticate(self)
        except exceptions.APIException:
            self._not_authenticated()
            raise

        if user_auth_tuple is not None:
            self._authenticator = authenticator
            self.user, self.auth = user_auth_tuple
            return

    self._not_authenticated()
  • 4.7:循环执行authenticate方法,即我们自定义的认证类

标签:authenticate,04,self,request,rest,framework,token,user,def
From: https://www.cnblogs.com/xwltest/p/18209351

相关文章

  • Android11快速编译并替换framework.jar
    Android11快速编译并替换framework.jar在Android11之前修改了framework相关代码,只需makeframework就可以编译出framework.jar。在Android11,这个编译命令不起作用了,根据framework/base/目录下Android.bp中的提示:java_library{name:"framework-minus-apex",defaults:......
  • Ubuntu 22.04 使用self-service-password搭建自主修改密码平台
    Ubuntu系统安装准备正常操作是安装成功系统,安装的时候设置好静态密码。参考官方文档:https://self-service-password.readthedocs.io/en/stable/installation.html根据文档提示安装会报错,网上查了些资料需要按照如下步骤安装依赖。正式安装vi/etc/apt/sources.list.d/ltb-p......
  • 满足 5G 通信的带宽需求,1ST040EH2F35I2LG,1ST085ES3F50I3VG,1ST085ES3F50E3VG,1ST110E
    说明Stratix®10FPGA和SoCFPGA大幅提高了性能、功效、密度和系统集成度。Stratix10采用创新HyperflexFPGA架构,将嵌入式多芯片互连桥接器(EMIB)、高级接口总线(AIB)和芯片组等技术结合在一起。™因此,与上一代高性能FPGA相比,Stratix10器件的性能提高了2倍。Stratix®10......
  • utools插件开发踩坑记录 - vite+recat搭建打包到utools环境时运行页面报错unexpected
    问题现象在本地开发环境时,运行无问题,一但打包到utools环境运行时,就出现了下面的现象依赖"dependencies":{"@ant-design/icons":"^5.3.7","antd":"^5.17.3","react":"^18.2.0","react-dom":"^......
  • CSP历年复赛题-P1046 [NOIP2005 普及组] 陶陶摘苹果
    原题链接:https://www.luogu.com.cn/problem/P1046题意解读:30+伸手的高度,能够得着几个苹果。解题思路:直接模拟。100分代码:#include<bits/stdc++.h>usingnamespacestd;inta[15],h,ans;intmain(){for(inti=1;i<=10;i++)cin>>a[i];cin>>h;......
  • CSP历年复赛题-P1087 [NOIP2004 普及组] FBI 树
    原题链接:https://www.luogu.com.cn/problem/P1087题意解读:字符串作为根,左边一半作为左子树,右边一半作为右子树,递归构造数,并按FBI规则输出后续遍历结果。解题思路:按照题意,通过dfs来构造树,对于字符串str,提取左边一半递归构造左子树,提取右边一半递归构造右子树,前提是字符串长度>1......
  • CSP历年复赛题-P1085 [NOIP2004 普及组] 不高兴的津津
    原题链接:https://www.luogu.com.cn/problem/P1085题意解读:找到两数之和大于8且两数之和最大值的位置解题思路:不多说,送分题,直接模拟法即可100分代码:#include<bits/stdc++.h>usingnamespacestd;inta,b;intmaxx,maxn;intmain(){for(inti=1;i<=7;i++)......
  • Ubuntu 22.04.4 深度学习环境配置
    显卡为NVIDIA4090D 显卡驱动安装成功后,输入以下命令,查看驱动支持最高的CUDA版本。nvidia-smi一、CUDA安装(1)官网下载对应CUDA(NvidiaCUDADownload / CUDAToolkitArchive|NVIDIADeveloper)以CUDA11.8为例(师兄用12.2也未冲突)  (2)驱动安装开网上推荐安装runfil......
  • 【DRF-03】rest-framework之APIView
    安装djangorestframeworkpipinstalldjangorestframework基本流程:url--》视图类--》执行dispatch方法fromrest_framework.viewsimportAPIViewfromrest_framework.responseimportResponseclassTestView(APIView):defdispatch(self,request,*args,*......
  • RestFul API风格(规范)
     在现代web开发中,API(应用程序编程接口)扮演着至关重要的角色。它们使得不同的应用程序能够彼此通信,共享数据和功能。在众多API设计风格中,RESTful风格因其简洁性和高效性而备受推崇。本文将带你深入了解RESTful风格,探索其基本原则和最佳实践。 1.什么是RESTful风......