• drf--认证组件


    认证简介

    使用场景:有些接口在进行访问时,需要确认用户是否已经登录,比如:用户需要购买物品时,在结账的时候,就需要进行登录验证的。

    用户认证RBAC(Role-Based Access Control)

    一般用户认证都是基于角色认证:

    • 三表机制

      • 用户表(User)
      • 角色表(Group)
      • 权限表(Permission)

      用户表关联角色表,角色表关联权限表

    • 五表机制

      • 用户表(User)
      • 用户角色关系表(User-Group)
      • 角色表(Group)
      • 角色权限表(Group-Permission)
      • 权限表(Permission)

      用户表与角色表多对多、角色表与权限表多对多

    • Django采用六表机制

      • 用户表(User)
      • 用户角色关系表(User-Group)
      • 角色表(Group)
      • 角色权限表(Group-Permission)
      • 权限表(Permission)
      • 角色权限表(User-Permission)

      用户表与角色表多对多、角色表与权限表多对多、用户表和权限表多对多

    局部使用

    • models.py
    from django.contrib.auth import models
    
    class User(models.Model):
        username=models.CharField(max_length=32)
        password=models.CharField(max_length=32)
        user_type=models.IntegerField(choices=((1,'超级用户'),(2,'普通用户'),(3,'二B用户')))
    
    class UserToken(models.Model):
        user=models.OneToOneField(to='User')
        token=models.CharField(max_length=64)
    
    • 自定义认证类
    from rest_framework.authentication import BaseAuthentication
    
    class TokenAuth():
        def authenticate(self, request):
            token = request.GET.get('token')
            token_obj = models.UserToken.objects.filter(token=token).first()
            if token_obj:
                return
            else:
                raise AuthenticationFailed('认证失败')
                
        def authenticate_header(self,request):
            pass
    
    • views.py
    def get_random(name):
        import hashlib
        import time
        md=hashlib.md5()
        md.update(bytes(str(time.time()),encoding='utf-8'))
        md.update(bytes(name,encoding='utf-8'))
        return md.hexdigest()
    
    
    class Login(APIView):
        def post(self,reuquest):
            back_msg={'status':1001,'msg':None}
            try:
                name=reuquest.data.get('name')
                pwd=reuquest.data.get('pwd')
                user=models.User.objects.filter(username=name,password=pwd).first()
                if user:
                    token=get_random(name)
                    models.UserToken.objects.update_or_create(user=user,defaults={'token':token})
                    back_msg['status']='1000'
                    back_msg['msg']='登录成功'
                    back_msg['token']=token
                else:
                    back_msg['msg'] = '用户名或密码错误'
            except Exception as e:
                back_msg['msg']=str(e)
            return Response(back_msg)
    
    
    class Course(APIView):
        authentication_classes = [TokenAuth, ]
    
        def get(self, request):
            return HttpResponse('get')
    
        def post(self, request):
            return HttpResponse('post')
    
    • 进阶:不存数据库的token验证

      def get_token(id,salt='123'):
          import hashlib
          md=hashlib.md5()
          md.update(bytes(str(id),encoding='utf-8'))
          md.update(bytes(salt,encoding='utf-8'))
          return md.hexdigest()+'|'+str(id)
      
      def check_token(token,salt='123'):
          ll=token.split('|')
          import hashlib
          md=hashlib.md5()
          md.update(bytes(ll[-1],encoding='utf-8'))
          md.update(bytes(salt,encoding='utf-8'))
          if ll[0]==md.hexdigest():
              return True
          else:
              return False
      
      class TokenAuth():
          def authenticate(self, request):
              token = request.GET.get('token')
              success=check_token(token)
              if success:
                  return
              else:
                  raise AuthenticationFailed('认证失败')
          def authenticate_header(self,request):
              pass
          
      class Login(APIView):
          def post(self,reuquest):
              back_msg={'status':1001,'msg':None}
              try:
                  name=reuquest.data.get('name')
                  pwd=reuquest.data.get('pwd')
                  user=models.User.objects.filter(username=name,password=pwd).first()
                  if user:
                      token=get_token(user.pk)
                      # models.UserToken.objects.update_or_create(user=user,defaults={'token':token})
                      back_msg['status']='1000'
                      back_msg['msg']='登录成功'
                      back_msg['token']=token
                  else:
                      back_msg['msg'] = '用户名或密码错误'
              except Exception as e:
                  back_msg['msg']=str(e)
              return Response(back_msg)
          
          
      from rest_framework.authentication import BaseAuthentication
      
      class TokenAuth():
          def authenticate(self, request):
              token = request.GET.get('token')
              token_obj = models.UserToken.objects.filter(token=token).first()
              if token_obj:
                  return
              else:
                  raise AuthenticationFailed('认证失败')
          def authenticate_header(self,request):
              pass
      
      class Course(APIView):
          authentication_classes = [TokenAuth, ]
      
          def get(self, request):
              return HttpResponse('get')
      
          def post(self, request):
              return HttpResponse('post')
      

    总结:局部使用,只需要在视图类里加入:

    authentication_classes = [TokenAuth, ]
    

    全局使用

    全局使用需要在setting.py中进行配置

    REST_FRAMEWORK={
        "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",]
    }
    

    源码分析

    # Request对象的user方法
    
    @property
    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 = 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()
    
    def _not_authenticated(self):
    	"""
    	Set authenticator, user & authtoken representing an unauthenticated request.
    Defaults are None, AnonymousUser & None.
    	"""
        self._authenticator = None
        if api_settings.UNAUTHENTICATED_USER:
            self.user = api_settings.UNAUTHENTICATED_USER()
        else:
            self.user = None
    
        if api_settings.UNAUTHENTICATED_TOKEN:
            self.auth = api_settings.UNAUTHENTICATED_TOKEN
            ()
        else:
            self.auth = None  
      
    
    # self.authenticators
    def get_authenticators(self):
    	return [auth() for auth in self.authentication_classes]
    

    认证类使用顺序:先用视图类中的验证类,再用settings里配置的验证类,最后用默认的验证类

  • 相关阅读:
    NOI 2016 区间 解题报告
    有关莫队
    [JSOI2008]最大数 线段树解法
    HDU P3341 Lost's revenge 题解+数据生成器
    BZOJ P1212 [HNOI2004] L语言
    洛谷P3168 [CQOI2015]任务查询系统
    普通平衡树Tyvj1728、luogu P3369 (splay)
    洛谷P3384 树链剖分
    BZOJ P2157 旅游
    【算法导论】第6章,堆排序
  • 原文地址:https://www.cnblogs.com/Hades123/p/11714727.html
Copyright © 2020-2023  润新知