Django Rest Framwork(认证,权限,频率)简单使用(一)
django-rest-framework中的认证,权限,频率是进程APIVie类
APIView继承View类:
1、在APIView中request先进行as_view然后调用父类的As_view调用dispatch,由于APiview重写了dispatch,所以调用APIView中的dispatch
class APIView(View): # The following policies may be set at either globally, or per-view. renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES parser_classes = api_settings.DEFAULT_PARSER_CLASSES authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES #这是访问认证的全局配置 throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES #这是访问频率控制 permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES #这是权限控制的配置,如果在实列中没有定义,则用全局配置 content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS metadata_class = api_settings.DEFAULT_METADATA_CLASS versioning_class = api_settings.DEFAULT_VERSIONING_CLASS # Allow dependency injection of other settings to make testing easier. settings = api_settings schema = DefaultSchema() @classmethod def as_view(cls, **initkwargs): """ Store the original class on the view function. This allows us to discover information about the view when we do URL reverse lookups. Used for breadcrumb generation. """ if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet): def force_evaluation(): raise RuntimeError( 'Do not evaluate the `.queryset` attribute directly, ' 'as the result will be cached and reused between requests. ' 'Use `.all()` or call `.get_queryset()` instead.' ) cls.queryset._fetch_all = force_evaluation view = super(APIView, cls).as_view(**initkwargs) #调用父类的as_view,反射调用dispatch() view.cls = cls view.initkwargs = initkwargs # Note: session based authentication is explicitly CSRF validated, # all other authentication is CSRF exempt. return csrf_exempt(view)
2、dispatch
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 #1.对原来的request进行加工,initialize_requset request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate? try:
#初始化验证,如果不报错则执行下面的反射方法,否则报错引发异常 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
dispatch重写
1.先进行request丰富
def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. """ parser_context = self.get_parser_context(request) #对原生的request进行二次丰富 #在Request中对原生的request self._request=request,则self._request表示原生的request # 在Request类中,self.authenticators = authenticators or () ,而 authenticators=self.get_authenticators()这段代码中, # get_authenticators()的方法 return [auth() for auth in self.authentication_classes],返回一个类的实列化列表 return Request( request, parsers=self.get_parsers(), # return [auth() for auth in self.authentication_classes] authenticators=self.get_authenticators(), #返回对象obj()实列化对象,更具authentication_classes中的返回的类 negotiator=self.get_content_negotiator(), parser_context=parser_context )
2.然后再进行初始化执行self.perform_authentication(request),self.chek_perimission(request),self.check_throttles(request),当然这些方法都可以在中间见中实现
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)#对用户验证 (并且request.user,request.auth赋值)
self.check_permissions(request) #权限验证 self.check_throttles(request) #频率验证
1.认证:
解剖,class View中的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
#request.user在这个dispatch中,对request丰富的时候,调用的initial_request()方法里面封装request用的Request()类实列,
#也就是说,perform_authentication(self,request)返回的是Request类中的user方法
下面来看一下Request类中的user是什么:
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
def _authenticate(self): """ Attempt to authenticate the request using each authentication instance in turn. """ for authenticator in self.authenticators: try: #user_auth_tuple是none则不进行验证 #user_auth_tuple如果不是None则执行下面的验证赋值,返回 request.user ,request.auth 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()
一、rest认证
在RestView.py中定义如下:
def token_md5(username): """ :Function: 生成随机字符串Md5, :param username: :return: Md5随机字符串 """ import hashlib import time ctime = str(time.time()) token_a = hashlib.md5(bytes(username, encoding='utf-8')) token_a.update(bytes(ctime, encoding='utf-8')) return token_a.hexdigest()
class AuthView(APIView): """ 用户登录,设置token随机字符串 """ authentication_classes = [] permission_classes = []
#throttle_classes=[] def post(self, request, *args, **kwargs): ret = {'code': 1000, 'msg': None} username = request._request.POST.get('username') passwd = request._request.POST.get('passwd') obj = models.User.objects.filter(username=username, passwd=passwd).first() if not obj: ret['code'] = 1001 ret['msg'] = "登录失败" else: token = token_md5(username) ret['token'] = token ret['code'] = 200 ret['msg'] = '登录成功' # token数据中添加token随机字符串 co, created = models.UserToken.objects.update_or_create(user=obj, defaults={'token': token}) return JsonResponse(ret, json_dumps_params={'ensure_ascii': False})#这边要写ensure_ascii:False保证中文不乱吗
在App的utils中定义auth(认证),permission(权限),Mythrottling(访问频率)
utils中的auth.py
from cmdb import models from rest_framework import exceptions from rest_framework.authentication import BaseAuthentication class Authenticate(BaseAuthentication): """ 用户认证 """ def authenticate(self, request, *args, **kwargs): """ :Function: 验证是否含有token随机字符串 :param request: :param args: :param kwargs: :return: request.user, request.auth 请求用户名和认证 """ token_obj = request._request.GET.get('token') select_auth_result = models.UserToken.objects.filter(token=token_obj).first() if not select_auth_result: raise exceptions.AuthenticationFailed('登录失败oo!') return (select_auth_result.user, select_auth_result)#源码中返回一个user,和一个auth的元组 def authenticate_header(self,request): pass
permission.py:
from rest_framework.permissions import BasePermission class VipUserPermission(BasePermission): message='你不是Svip用户,没有权利访问' def has_permission(self, request, view): if request.user.user_type != 3: return False return True
Mythrottlings.py:
from rest_framework.throttling import BaseThrottle, SimpleRateThrottle class My_login_throtte(SimpleRateThrottle): scope = 'AuthGet' def get_cache_key(self, request, view): return self.get_ident(request)
在全局settings配置中配置如下:
REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ['cmdb.utils.auth.Authenticate', ], # 其中写认证的类的路径,不要在views中,这里我放在了utils目录下auth.py中 "UNAUTHENTICATED_USER": lambda: "匿名", # 匿名用户配置,只需要函数或类的对应的返回值,对应request.user="匿名" "UNAUTHENTICATED_token": None, # 匿名token,只需要函数或类的对应的返回值,对应request.auth=None "DEFAULT_PERMISSION_CLASSES" : ['cmdb.utils.permission.VipUserPermission',], #权限控制 "DEFAULT_THROTTLE_CLASSES" : ['cmdb.utils.Mythrottling.My_login_throtte',], #访问频率控制 "DEFAULT_THROTTLE_RATES":{ 'AuthGet': '5/m', } #设置源码中的rate值
}
在指定的视图中用
authentication_classes = []
permission_classes = []
throttle_classes=[]
来表示不适用全局配置: