当前位置:   article > 正文

Django:drf实现简单认证、权限管理、限流功能_django drf 微服务权鉴

django drf 微服务权鉴

Django:drf实现简单认证、权限管理、限流功能

一、drf是如何在Django的框架上进行前后端交互

1. 封装Django原生request

目的:在原来的request对象基础中再进行封装一些drf中需要用到的值。比如认证、权限管理、限流。
1.1图一

1.2图二
由上面的代码可知drf将Django原生request对象封装成Request对象,并且初始化authenticators参数,该参数正是认证功能。

那么一个请求到达后台后,Django和drf的执行顺序是如何的呢?

# urls.py
from django.urls import path
from web.views import UserView

urlpatterns = [
	path('user/', UserView.as_view()),
]

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

# web/views.py
class UserView(APIView):
	# 接收get请求时的处理
	def get(self, request):
		return Response("...")

	def post(self, request):
		return Response("post")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  1. 路由匹配后,进入到drf的APIView的as_view接口,接着调用父类的as_view,由下图源码可知,APIView的父类是Django源码的View对象;
    在这里插入图片描述
  2. Django的View中则是使用APIView类实例化对象self,然后调用drf中APIView的dispatch,里面则是封装Django原生request对象
    在这里插入图片描述
    在这里插入图片描述
  3. 接着根据Django的request对象获取请求方式,然后在视图类查找是否有相应的方法,如果没有则报错。然后就执行视图类中的方法。

二、认证

2.1 某个视图定制自己的认证规则


# web/views.py
from rest_framework.views import APIView
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed

class MyAuthentication(BaseAuthentication):
	def authenticate(self, request):
		token = request.query_params.get("token", "")
		if not token:
			raise AuthenticationFailed({"code":1002, "detail":"未登录不可访问"})


class UserView(APIView):
	authentication_classes = [MyAuthentication,]

	# 接收get请求时的处理
	def get(self, request, *args, **kwargs):
		return Response("...")

	def post(self, request, *args, **kwargs):
		return Response("post")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

2.2 多个视图公用一个认证规则

由于存在多个视图公用一个认证规则的情况,那么如果按照2.1中的方式每个视图类都添加一个认证类,那么是极不方便,对此drf提供了一个全局配置解决这个问题。

注意:认证组件的类不能放在视图view.py中,会因为导入APIView导致循环引用

# ext/auth.py
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed

class MyAuthentication(BaseAuthentication):
	def authenticate(self, request):
		token = request.query_params.get("token", "")
		if not token:
			raise AuthenticationFailed({"code":1002, "detail":"未登录不可访问"})

# settings.py
# 在源码可以知道默认读取配置类中的认证类
REST_FRAMEWORK = {
    "UNAUTHENTICATED_USER": None,
    "DEFAULT_AUTHENTICATION_CLASSES": ["ext.auth.MyAuthentication"],
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在这里插入图片描述

2.3 认证是如何实现的

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
首次执行,没有_user对象,那么就会执行_authenticate,这里面就会遍历Request创建时设置的认证类,并且由此可以知道,当一个视图类拥有多个认证类时,只要有一个认证类满足条件返回数值,后续的认证类就不再执行;但如果都不满足,也不会影响视图函数的执行,只不过 self.user self.auth = None。
在这里插入图片描述在这里插入图片描述

2.4 使用场景

结合源码分析,认证模块可以用来处理用户登录需求,在认证类中返回用户对象和token即可在后续调用request.user获取到用户。

拓展:状态码一致问题

例如raise了AuthenticationFailed,他的错误码是401,但实际显示的是403
在这里插入图片描述在这里插入图片描述

原因:

在drf的dispatch中捕捉报错后执行的handle_exception,假如错误是AuthenticationFailed,那就会去认证类中获取authenticate_header函数,如果获取不到就会设置403作为状态码。
在这里插入图片描述

权限

class UserPermission(BasePermission):
    message = {"status": False, 'msg': "无权访问1"}

    def has_permission(self, request, view):
        if request.user.role == 3:
            return True
        return False

class UserView(NbApiView):
    # 经理、总监、用户
    permission_classes = [UserPermission,]

    def get(self, request):
        return Response("UserView")

    def post(self, request):
        return Response("UserView")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

权限类共用,那么就在settings中配置即可
在这里插入图片描述

REST_FRAMEWORK = {
    "UNAUTHENTICATED_USER": None,
    "DEFAULT_PERMISSION_CLASSES":[
        "ext.per.UserPermission"
    ]

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

源码分析:

在这里插入图片描述
在这里插入图片描述

由源码可知,如果有多个权限类,那么只要有一个权限类不通过,那么就停止后续权限类的检测。如果希望调整检测规则,则覆写check_permission即可。

限流

限流组件需要存储用户访问次数,那么可以采用redis缓存这些数据就可以达成目的
在这里插入图片描述

class UserThrottle(SimpleRateThrottle):
    scope = "user"  # 用于获取THROTTLE_RATES中的频率
    cache = default_cache  # 使用的redis
	THROTTLE_RATES = {"user": "10/m"}  # 设置频率
	# 获取唯一标识
    def get_cache_key(self, request, view):
        ident = request.user.pk  # 用户ID
        return self.cache_format % {'scope': self.scope, 'ident': ident}

class UserView(APIView):
    # 经理、总监、用户
   	throttle_classes = [UserThrottle, IpThrottle]

    def get(self, request):
        return Response("UserView")

    def post(self, request):
        return Response("UserView")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

共用限流类,那么就在settings中配置即可

REST_FRAMEWORK = {
    "DEFAULT_THROTTLE_RATES": {
        "ip": "10/m",
        "user": "5/m"
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

源码分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

由源码知,他会遍历所有的限流类,如果访问次数超过限流类的限制次数,那么就会获取等待时间加入列表,然后显示等待时间最长的限制类显示给用户看。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/963239
推荐阅读
相关标签
  

闽ICP备14008679号