赞
踩
目的:在原来的request对象基础中再进行封装一些drf中需要用到的值。比如认证、权限管理、限流。
由上面的代码可知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")
# 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")
由于存在多个视图公用一个认证规则的情况,那么如果按照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"], }
首次执行,没有_user对象,那么就会执行_authenticate,这里面就会遍历Request创建时设置的认证类,并且由此可以知道,当一个视图类拥有多个认证类时,只要有一个认证类满足条件返回数值,后续的认证类就不再执行;但如果都不满足,也不会影响视图函数的执行,只不过 self.user self.auth = None。
结合源码分析,认证模块可以用来处理用户登录需求,在认证类中返回用户对象和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")
权限类共用,那么就在settings中配置即可
REST_FRAMEWORK = {
"UNAUTHENTICATED_USER": None,
"DEFAULT_PERMISSION_CLASSES":[
"ext.per.UserPermission"
]
}
由源码可知,如果有多个权限类,那么只要有一个权限类不通过,那么就停止后续权限类的检测。如果希望调整检测规则,则覆写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")
共用限流类,那么就在settings中配置即可
REST_FRAMEWORK = {
"DEFAULT_THROTTLE_RATES": {
"ip": "10/m",
"user": "5/m"
}
}
由源码知,他会遍历所有的限流类,如果访问次数超过限流类的限制次数,那么就会获取等待时间加入列表,然后显示等待时间最长的限制类显示给用户看。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。