广告位联系
返回顶部
分享到

drf-router和authenticate认证源码

python 来源:转载 作者:秩名 发布时间:2021-07-11 07:54:19 人浏览
摘要

一、路由Routers 在 Rest Framework 中提供了两个 router , 可以帮助我们快速的实现路由的自动生成。 必须是继承 ModelViewSet 的视图类才能自动生成路由 SimpleRouter 使用方法: urls.py # 第一步:导入routers模块from rest_framework import routers# 第

一、路由Routers

在 Rest Framework 中提供了两个 router , 可以帮助我们快速的实现路由的自动生成。

必须是继承 ModelViewSet 的视图类才能自动生成路由

SimpleRouter

使用方法:

urls.py

# 第一步:导入routers模块
from rest_framework import routers

# 第二步:实例化得到对象
router = routers.SimpleRouter() 

# 第三步:注册( register('前缀', viewset视图集, 路由的别名) )
router.register('books', views.BooksViewset)

# 第四步:生成路由加入到原路由中
# 方式一:
urlpatterns = [
    ...
]
urlpatterns += router.urls

# 方式二:
urlpatterns = [
    ...
    url(r'^', include(router.urls))
]


# 形成路由如下
<URLPattern '^books/$' [name='books-list']>
<URLPattern '^books/(?P<pk>[^/.]+)/$' [name='books-detail']>

DefaultRouter

DefaultRouter与SimpleRouter的区别是,DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据。

# 前两条和SimpleRouter一样
<URLPattern '^books/$' [name='books-list']>
<URLPattern '^books/(?P<pk>[^/.]+)/$' [name='books-detail']>

# 效果也和前两条类似,
# 如:http://127.0.0.1:8000/books.json
<URLPattern '^books\.(?P<format>[a-z0-9]+)/?$' [name='books-list']>
# http://127.0.0.1:8000/books/1.json
<URLPattern '^books/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$' [name='books-detail']>

# 多了个根路由http://127.0.0.1:8000/
<URLPattern '^$' [name='api-root']>, <URLPattern '^\.(?P<format>[a-z0-9]+)/?$' [name='api-root']>

action的使用

action是为了给继承自 ModelViewSet 的视图类中自定义的函数也添加路由

例如下面这样:

from rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response
from app01.ser import BooksSerializers
from app01.models import Books


class BooksViewSet(ModelViewSet):
    queryset = Books.objects.all()
    serializer_class = BooksSerializers

    # 这种方法不会自动生成,需要用action配置
    def get_num(self, request, pk):
        book = self.get_queryset()[:int(pk)]
        ser = self.get_serializer(book, many=True)
        return Response(ser.data)

使用示例:

action是一个装饰器,放在被装饰的函数上方,

method:请求方式

detail:是否带pk ——>True 表示路径格式是xxx/<pk>/action方法名/——False 表示路径格式是xxx/action方法名/

from rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response
from rest_framework.decorators import action
from app01.ser import BooksSerializers
from app01.models import Books


class BooksViewSet(ModelViewSet):
    queryset = Books.objects.all()
    serializer_class = BooksSerializers

    @action(methods=['GET', 'POST'], detail=True)
    def get_num(self, request, pk):
        book = self.get_queryset()[:int(pk)]    # 获取前几条数据
        ser = self.get_serializer(book, many=True)
        return Response(ser.data)
    
    
# 生成路由如下
http://127.0.0.1:8000/books/2/get_num/
<URLPattern '^books/(?P<pk>[^/.]+)/get_num/$' [name='books-get-num']>

二、认证

认证的写法

  • 写一个认证类,继承 BaseAuthentication,重写 authenticate, 认证的逻辑写在里面,认证通过,返回两个值,一个值给Request对象的user, 认证失败,抛异常:APIException或者AuthenticationFailed
  • 将认证类添加到需要认证视图类的authentication_classes = [认证类1]中
  • 全局使用,还是局部使用
# 全局使用,在setting.py中配置
REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.app_auth.MyAuthentication",]
}

# 局部使用,在视图类上写
authentication_classes=[MyAuthentication]
# 局部禁用
authentication_classes=[]

认证源码分析

1、APIView重写as_view方法使之没有csrf认证——>但还是正常执行 dispatch 方法,但是 dispatch方法被 APIView重写了——>dispatch 中执行了 self.initial 认证方法——>有认证,权限,频率

2、现在只是看认证源码self.perform_authentication(request)

3、但是self.perform_authentication(request)就一句话:request.user,那么就需要去 drf 的 Request 对象中找 user 属性(方法)

@property
def user(self):
    # 先去判断当前对象中有没有'_user'这个属性,一开始肯定是没有的,因为用户是没有登录的
    if not hasattr(self, '_user'):
        with wrap_attributeerrors():
            # 没有用户,认证出用户
            self._authenticate()
    # 有用户,直接返回用户
    return self._user

4、Request 类中的 user 方法,刚开始来,没有_user,走 self._authenticate()

5、核心,就是Request类中的 _authenticate(self)

def _authenticate(self):
    
    # 遍历拿到一个认证器,进行认证
    # self.authenticators 配置的一堆认证类产生的认证类对象组成的 list
    # self.authenticators 就是在视图类中配置的:authentication_classes = [认证类1,认证类2] 的一个个认证类的对象:
    
    ————>self.authenticators ==》 [认证类1对象,认证类2对象]
    for authenticator in self.authenticators:
        try:
            
            # 认证器调用认证方法authenticate(认证类对象self,request对象)
            """
            def authenticate(self, request):
                return (self.force_user, self.force_token)
            """
            # 返回值:登录的用户与认证的信息组成的 tuple
            # 并且该方法被try包裹,就代表该方法会抛异常,抛异常就代表认证失败
            user_auth_tuple = authenticator.authenticate(self) # self是request对象
        except exceptions.APIException:
            self._not_authenticated()
            raise
        
        # 返回值的处理
        if user_auth_tuple is not None:
            self._authenticator = authenticator
            # 如果有返回值,就将 "登录用户" 与 "登录认证" 分别保存到 request.user / request.auth
            self.user, self.auth = user_auth_tuple
            return
    # 如果返回值user_auth_tuple为空,代表认证通过,但是没有 "登录用户" 与 "登录认证信息",代表游客
    self._not_authenticated()

认证组件的使用

1、写一个认证类,继承 BaseAuthentication,重写 authenticate

# app01_auth.py
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from app01.models import UserToken


class TokenAuthentication(BaseAuthentication):
    def authenticate(self, request):
        # 认证逻辑,如果认证通过,返回两个值
        # 如果认证失败,抛出AuthenticationFailed异常
        token = request.data.get('token')
        if token:
            user_token = UserToken.objects.filter(token=token).first()

            # 认证通过
            if user_token:
                return UserToken.user, token
            else:
                raise AuthenticationFailed('认证失败')
        else:
            raise AuthenticationFailed('请求地址中需要带token')

2、将认证类添加到需要认证视图类的authentication_classes = [认证类1]中

 
# views.py
from rest_framework.viewsets import ModelViewSet
from rest_framework.views import APIView
from rest_framework.response import Response
from app01.models import Books, UserInfo, UserToken
from app01.ser import BooksSerializer
from app01.app01_auth import TokenAuthentication
import uuid


# 查看Books需要经过认证才能查看
class BooksView(ModelViewSet):
    authentication_classes = [TokenAuthentication]

    queryset = Books.objects.all()
    serializer_class = BooksSerializer


# 登录视图,登录后获得token,后续用token认证
class LoginView(APIView):

    def post(self, request):
        response_msg = {'status': 200, 'msg': ''}
        username = request.data.get('username')
        password = request.data.get('password')
        user_obj = UserInfo.objects.filter(username=username, password=password).first()

        if user_obj:
            # 登录成功生成一个随机字符串
            token = uuid.uuid4()
            
            # 存到UserToken表中,update_or_create有就更新,没有就新增
            UserToken.objects.update_or_create(defaults={'token': token}, user=user_obj)
            response_msg['msg'] = '登录成功'
            response_msg['token'] = token
        else:
            response_msg['msg'] = '账户或密码错误'
            response_msg['status'] = 204
        return Response(response_msg)


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。

您可能感兴趣的文章 :

原文链接 : https://www.cnblogs.com/XiaoYang-sir/p/14993045.html
相关文章
  • Python Django教程之实现新闻应用程序

    Python Django教程之实现新闻应用程序
    Django是一个用Python编写的高级框架,它允许我们创建服务器端Web应用程序。在本文中,我们将了解如何使用Django创建新闻应用程序。 我们将
  • 书写Python代码的一种更优雅方式(推荐!)

    书写Python代码的一种更优雅方式(推荐!)
    一些比较熟悉pandas的读者朋友应该经常会使用query()、eval()、pipe()、assign()等pandas的常用方法,书写可读性很高的「链式」数据分析处理代码
  • Python灰度变换中伽马变换分析实现

    Python灰度变换中伽马变换分析实现
    1. 介绍 伽马变换主要目的是对比度拉伸,将图像灰度较低的部分进行修正 伽马变换针对的是对单个像素点的变换,也就是点对点的映射 形
  • 使用OpenCV实现迷宫解密的全过程

    使用OpenCV实现迷宫解密的全过程
    一、你能自己走出迷宫吗? 如下图所示,可以看到是一张较为复杂的迷宫图,相信也有人尝试过自己一点一点的找出口,但我们肉眼来解谜
  • Python中的数据精度问题的介绍

    Python中的数据精度问题的介绍
    一、python运算时精度问题 1.运行时精度问题 在Python中(其他语言中也存在这个问题,这是计算机采用二进制导致的),有时候由于二进制和
  • Python随机值生成的常用方法

    Python随机值生成的常用方法
    一、随机整数 1.包含上下限:[a, b] 1 2 3 4 import random #1、随机整数:包含上下限:[a, b] for i in range(10): print(random.randint(0,5),end= | ) 查看运行结
  • Python字典高级用法深入分析讲解
    一、 collections 中 defaultdict 的使用 1.字典的键映射多个值 将下面的列表转成字典 l = [(a,2),(b,3),(a,1),(b,4),(a,3),(a,1),(b,3)] 一个字典就是一个键对
  • Python浅析多态与鸭子类型使用实例
    什么多态:同一事物有多种形态 为何要有多态=》多态会带来什么样的特性,多态性 多态性指的是可以在不考虑对象具体类型的情况下而直
  • Python字典高级用法深入分析介绍
    一、 collections 中 defaultdict 的使用 1.字典的键映射多个值 将下面的列表转成字典 l = [(a,2),(b,3),(a,1),(b,4),(a,3),(a,1),(b,3)] 一个字典就是一个键对
  • Python淘宝或京东等秒杀抢购脚本实现(秒杀脚本

    Python淘宝或京东等秒杀抢购脚本实现(秒杀脚本
    我们的目标是秒杀淘宝或京东等的订单,这里面有几个关键点,首先需要登录淘宝或京东,其次你需要准备好订单,最后要在指定时间快速
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计