首页 > 其他分享 >drf : 认证 频率 权限

drf : 认证 频率 权限

时间:2024-03-25 13:11:07浏览次数:20  
标签:get models self request 认证 token user 权限 drf

编写登录功能引出认证,权限,频率:

前端通过接口测试工具Postman将用户名和密码通过HTTP请求发送至Django框架

models.py

from django.db import models


# Create your models here.
class Books(models.Model):
    name = models.CharField(max_length=32)
    price = models.IntegerField()
    publish = models.ForeignKey(to='Publish', on_delete=models.DO_NOTHING)


class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)


class User(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)


"""
用户登录生成随机字符串,响应中携带字符串,发送至服务端后,服务端做逻辑判断。
一般一对一为垂直分表。数据库优化的手段
"""
class UserToken(models.Model):
    user = models.OneToOneField(to='User', on_delete=models.CASCADE)
    token = models.CharField(max_length=64)

模型层拓展:

字段参数可以填写函数名,但不是不能加括号。

views.py

from rest_framework.views import APIView
from . import models
import uuid
from rest_framework.response import Response


class UserAPIView(APIView):
    def post(self,request,*args,**kwargs):
        back_dic = {'code':200,'msg':''}
        username = request.data.get('username')
        password = request.data.get('password')
        # 过滤出user表中含有请求中携带的数据,username,password.
        user = models.User.objects.filter(username=username,password=password).first()
        print(user)

        if user:
            """
            有用户的情况下
            登录成功之后生成token
            user=user,根据user查询,查询不到使用defaults新增,查询到更新。
            """
            # 生成随机字符串,请求中携带随机字符传
        		token = str(uuid.uuid4())
            models.UserToken.objects.update_or_create(defaults={'token': token}, user=user)
            back_dic['msg'] = '随机字符串更新'
            back_dic['token'] = token
        else:
            back_dic['code'] = 201
            back_dic['msg'] = '用户名或者密码错误'
        return Response(back_dic)

此时客户端发送post请求,后端验证正确会产生一条新的token覆盖原有的token。

认证,权限,频率所在位置。


APIView --> dispath(重写了request方法) --> initial(认证,权限,频率)
    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
        """认证"""
        self.perform_authentication(request)
        """权限"""
        self.check_permissions(request)
        """频率"""
        self.check_throttles(request)

认证类的编写

之前提到过,如果代码不属于视图层就另开一个py文件。

认证:只有携带token随机字符串才可以访问某个路由。

urls.py


from app01 import views
from rest_framework.routers import SimpleRouter, DefaultRouter
from django.urls import path, include

router = SimpleRouter()
router.register('books', views.BookAPIView)

urlpatterns = [
    # path('books/',views.BookAPIView.as_view({'get':'login'})),
    path('', include(router.urls)),
    path('login/', views.UserAPIView.as_view())
]

views.py

from .auth import LoginAuth
from rest_framework.generics import ListAPIView
from rest_framework.viewsets import ViewSetMixin


class BookAPIView(ViewSetMixin, ListAPIView):
    queryset = Books.objects.all()
    serializer_class = BookSerializers
    # 增加登录认证
    authentication_classes = [LoginAuth]

auth.py

"""认证类"""
from rest_framework.authentication import BaseAuthentication
from . import models
from rest_framework.exceptions import AuthenticationFailed

class LoginAuth(BaseAuthentication):
    def authenticate(self,request):
        # 写认证规则
        # 取出用户携带的token
        # -注意:取get提交的数据,不要从request.GET中取,从request.query_params中取
        token = request.query_params.get('token')
        print(token)
        # 去数据库查询,token是否存在,存在表示登录了,不存在表示为登录
        user_token = models.UserToken.objects.filter(token=token).first()
        if user_token:
          	# 943ffc46-3826-47f9-a4de-ea9cd4bd23d6
            print(user_token.token)
            # User object (1),模型类对象
            print(user_token.user)
            # junjie
            print(user_token.user.username)
            return user_token.user,user_token.token
        raise AuthenticationFailed('您没有登录,认证失败')

此时想要访问books必须携带token才可以访问。

认证类的全局和局部使用

全局配置:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES':[
        'app01.auth.LoginAuth'
    ]
}

局部禁用配置:

class UserAPIView(APIView):
    authentication_classes = []

源码分析:

# APIView--->dispathch方法的-----》self.initial(request, *args, **kwargs)(497行)---》APIView的initial方法----》有三句话
self.perform_authentication(request)  # 认证
self.check_permissions(request)       # 权限
self.check_throttles(request)         # 频率



# self.perform_authentication(request)----》新的request对象的.user(是个方法,包装成了数据数属性)---》新的Request类中找到了user方法---》self._authenticate()-----》Request类中的_authenticate
    def _authenticate(self):
        for authenticator in self.authenticators: # 配置在视图类中认证类列表,实例化得到的对象
            try:
                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.authenticators,self是Request类的对象,authenticators属性是Request这个类在实例化的时候,传入的

# Request类在实例化的时候代码
    return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),  # 要看的
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )


# self.get_authenticators()是APIView的方法
def get_authenticators(self):
   	 	# 列表推导式
        return [auth() for auth in self.authentication_classes]
    	# 返回结果是我们配在视图类中自己写的认证类列表的对象
        return [LoginAuth(),]

权限组件

导入模块

from rest_framework.permissions import BasePermission

auth.py

from rest_framework.permissions import BasePermission

class UserPermission(BasePermission):
    def has_permission(self, request, view):
        """
        认证类走完再走权限类,所以request.user可以拿到当前登录用户
        """
        if request.user.user_type == 1:
            return True
        return False

全局配置使用:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'app01.auth.UserPermission',
    ],
}

局部使用:

class BookAPIView(ViewSetMixin, ListAPIView):
    queryset = Books.objects.all()
    serializer_class = BookSerializers
    # 增加登录认证
    authentication_classes = [LoginAuth]
    # 增加权限类
    permission_classes = [UserPermission]
```python
#### 局部禁用:
```python
    permission_classes = []

权限类源码解读

APIView --> dispath --> initial --> self.check_permissions(request) --》
def check_permissions(self, request):
  """
  for permission in self.get_permissions(),self.get_permissions()在哪?
  		通过源码可以看到是权限类的全局和局部配置。局部有优先局部,局部没有定义取全局,全局没有去内置。
      def get_permissions(self):
        return [permission() for permission in self.permission_classes]
  """
  for permission in self.get_permissions():
    """
    对应到auth.py中的权限类,如果为True,代码正常执行,如果为False,执行self.permission_denied
    """
    if not permission.has_permission(request, self):
      self.permission_denied(
        request,
        """
        反射,现在auth.py中的权限类找massage.
        """
        message=getattr(permission, 'message', None),
        code=getattr(permission, 'code', None)
      )
# message 自定义报错信息
def permission_denied(self, request, message=None, code=None):
    """
    If request is not permitted, determine what kind of exception to raise.
    """
    if request.authenticators and not request.successful_authenticator:
        raise exceptions.NotAuthenticated()
    raise exceptions.PermissionDenied(detail=message, code=code)

auth.py

class UserPermission(BasePermission):
    def has_permission(self, request, view):
        """
        认证类走完再走权限类,所以request.user可以拿到当前登录用户
        """
        if request.user.user_type == 1:
            return True
        return False

频率组件的使用

频率的作用: 可以对接口访问的频次进行限制,以减轻服务器压力。一般用于付费购买次数,投票等场景使用.

**导入模块: **

from rest_framework.throttling import SimpleRateThrottle

auth.py,写一个类,继承基类,重写get_cache_key方法


class MyThrottle(SimpleRateThrottle):
    # scope一定要写,字符串对应到settings.py中配置REST_FRAMEWORK。
    scope = 'ip_Throttle'

    def get_cache_key(self, request, view):
        # 请求头所包含的信息在META中
        # 127.0.0.1
        print(request.META.get('REMOTE_ADDR'))
        return request.META.get('REMOTE_ADDR')
#### settings.py,配置文件中一定要配置。

REST_FRAMEWORK = {
	# (一分钟访问三次),key要跟类中的scope对应
    'DEFAULT_THROTTLE_RATES':{
        'ip_Throttle':'3/m'  
    }
}

settings.py ,全局配置。

REST_FRAMEWORK = {
  	 # (一分钟访问三次),key要跟类中的scope对应
    'DEFAULT_THROTTLE_RATES':{
        'ip_Throttle':'3/m'  
    },
 		 # 全局配置
    'DEFAULT_THROTTLE_CLASSES': (
        'app01.auth.MyThrottle',
    ),
}

views.py,视图类中配置

class BookAPIView(ViewSetMixin, ListAPIView):
    # 局部使用
    throttle_classes = [MyThrottle,]

标签:get,models,self,request,认证,token,user,权限,drf
From: https://www.cnblogs.com/HeroZhang/p/18094147

相关文章

  • drf : 自动生成路由,视图层自定义方法,路由映射方法,action参数。
    扩展一个知识点:在Django中,代码只要顶格编写,程序一运行,代码将直接执行。drf路由Routers自动生成路由需要继承ViewSetMixin子类,重写了as_view()方法。导入模块:fromrest_frameworkimportrouters创建router对象,并注册视图集合,例如:router=SimpleRouter()router.registe......
  • drf : 通用视图类和(GenericAPIView)5个视图扩展类,九个视图子类,视图集。
    视图RESTframework提供了众多的通用视图基类与扩展类,以简化视图的编写。APIViewrest_framework.views.APIViewAPIView是RESTframework提供的所有视图的基类,继承自Django的View父类。GenericAPIView使用[通用视图类]继承自APIVIew,主要增加了操作序列化器和数据库查询的方......
  • drf : 序列化类使用many参数的作用,源码解析
    序列化类使用many参数的作用views.pyfromrest_framework.viewsimportAPIViewfrom.serizlizerimportBookSerializersfromrest_framework.responseimportResponsefrom.modelsimportBooksclassBookView(APIView):defpost(self,request):print(r......
  • drf : 请求(Request)与响应(Response),全局设置和局部设置drf的默认配置项。
    请求(Request)与响应(Response)请求(Request),当次的HTTP响应请求到Django中被封装成python中的对象request.data-POST,PUT请求的数据request.query_params-GET请求的数据RESTframework传入视图的request对象不再是Django默认的HttpRequest对象,而是RESTframework提供的......
  • Django 字段类型,字段参数,以及在drf中的使用。
    字段类型#models中CharField,DecimalField.....#记住的: CharFieldIntegerFieldFloatFieldDecimalFieldDateTimeFieldDateField#知道--》models中没有的---》反序列化的时候,前端传入的{name:lqz,age:19,hobby:[篮球,足球],wife:{name:lyf,age:38}} ListF......
  • drf : 模型类序列化器 以及扩展用法。
    模型类序列化器:serializer的升级。注意,此时表模型自身的校验规则也将映射过来。只需要在serializers中写一个模型类序列化器即可。serializer.py#模型类序列化器#此序列化类和表模型有对应关系,映射classPublishModelSerializer(serializers.ModelSerializer):class......
  • drf : source,定制序列化字段以及反序列化新增。局部钩子(validate_字段名),全局钩子(va
    source,SerializerMethodField,局部钩子,全局钩子serialzer.py:source用处对应字段:起别名,用处2对应方法:在表模型中定义一个方法,source可以与其关联用处3对应方法:可以当做字段第三种方法的扩展用法:使用程度高。model.pyfromdjango.dbimportmodels#Createyourmo......
  • drf : APIView执行流程和新的Request源码。APIView和Request对象分析
    DRF基本使用及执行流程分析1.继承APIView使用2.APIView的执行流程路由:path('Book1',view.Book.as_view())-->第二个参数是函数的内存地址-->APIView的as_view的执行结果-->本质还是用了View类的as_viewn内的viewc包函数,去掉了csrf的认证。-->当请求来......
  • drf: 序列化和反序列化, Django Rest_Framework 介绍也安装及使用。
    序列化与返序列化序列化:将python中的数据类型转换成指定数据类型发送给别人返序列化:接收别人发送过来的数据,返序列化成我们所需要的格式。eg::前端js提供过来的json数据,对于python而言就是字符串,我们需要进行反序列化换成模型类对象,这样我们才能把数据保存到数据库中。DjangoR......
  • drf : web应用模式,RESTful API规范,接口测试工具:Postman
    drf:web应用模式,RESTfulAPI规范,接口测试工具:PostmanWeb应用模式前后端不分离前后端分离API接口前后端交互的媒介WebAPI接口和一般的url链接还是有区别的,WebAPI接口简单概括有下面四大特点。url:长得像返回数据的url链接https://api.map.baidu.com/place/v2/search......