drf认证权限频率(代码片段)

chenwenyin chenwenyin     2022-12-06     133

关键词:

一 认证Authentication

认证组件:校验用户 - 游客、合法用户、非法用户
游客:代表校验通过,直接进入下一步校验(权限校验)
合法用户:代表校验通过,将用户存储在request.user中,再进入下一步校验(权限校验)
非法用户:代表校验失败,抛出异常,返回403权限异常结果

认证源码分析

#1 APIVIew----> dispatch方法----> self.initial(request, *args, **kwargs)---->有认证,权限,频率

#2 只读认证源码: self.perform_authentication(request)

#3 self.perform_authentication(request)中就一句话:request.user,(这里的request对象被dispatch方法中的self.initialize_request(request, *args, **kwargs)方法重新封装成了drf自己的request对象)所以需要去drf的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 initialize_request(self, request, *args, **kwargs):
    """
    Returns the initial request object.
    """
    parser_context = self.get_parser_context(request)

    return Request(
        request,
        parsers=self.get_parsers(),
        authenticators=self.get_authenticators(), # 获得一个列表,列表中是一个个类的对象
        negotiator=self.get_content_negotiator(),
        parser_context=parser_context
    )


def get_authenticators(self):
    """
    Instantiates and returns the list of authenticators that this view can use.
    """
    # authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES,自己在视图类中配置的认证类(一个列表,列表中是类名)
    return [auth() for auth in self.authentication_classes]


#4 Request类中的user方法,刚开始来,没有_user,走 self._authenticate()

#5 核心,就是Request类的 _authenticate(self):
def _authenticate(self):
    # 遍历拿到一个个认证器,进行认证
    # self.authenticators配置的一堆认证类产生的认证类对象组成的 list
    #self.authenticators 你在视图类中配置的一个个的认证类:authentication_classes=[认证类1,认证类2],对象的列表   
    for authenticator in self.authenticators: # 这里的authenticators就是在self.initialize_request中封装的authenticators,是一个列表,里面是你自定义的认证类的对象
        try:
            # 认证器(对象)调用认证方法authenticate(认证类对象self, request请求对象)
            # 返回值:登陆的用户与认证的信息组成的 tuple
            # 该方法被try包裹,代表该方法会抛异常,抛异常就代表认证失败
            user_auth_tuple = authenticator.authenticate(self) # 注意这self是request对象,authenticate就是你自定义的认证类中重写的authenticate方法
        except exceptions.APIException:
            self._not_authenticated()
            raise

        # 返回值的处理
        """
        !!!!如果你配置了多个认证类,一定要在最后一个认证类中返回值,否则后面的认证类执行不了
        """
        if user_auth_tuple is not None:
            self._authenticator = authenticator
            # 如果有返回值,就将 登陆用户 与 登陆认证 分别保存到 request.user、request.auth
            self.user, self.auth = user_auth_tuple
            return
    # 如果返回值user_auth_tuple为空,代表认证通过,但是没有 登陆用户 与 登陆认证信息,代表游客
    self._not_authenticated()

自定义认证方案

# models.py
class User(models.Model):
    username=models.CharField(max_length=32)
    password=models.CharField(max_length=32)
    user_type=models.IntegerField(choices=((1,‘超级用户‘),(2,‘普通用户‘),(3,‘二笔用户‘)))

class UserToken(models.Model):
    user=models.OneToOneField(to=‘User‘)
    token=models.CharField(max_length=64)


# auth.py(新建认证类)
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from app01.models import UserToken

class TokenAuth():
    # token方在url中
    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(‘认证失败‘)

    # token放在请求头中
    # def authenticate(self, request):
    #     #     token = request.META.get(‘HTTP_TOKEN‘, None) # 注意token被重新拼接了
    #     #     if not token:
    #     #         raise AuthenticationFailed(‘非法查看‘)
    #     #     obj = UserToken.objects.filter(token=token).first()
    #     #     if obj:
    #     #         return obj.user, token
    #     #     raise AuthenticationFailed(‘认证失败‘)


# views.py
from rest_framework.views import APIView
from app01 import models

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):
    authentication_classes = []
    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‘)

可以在配置文件中配置全局默认的认证方案

# drf默认配置
REST_FRAMEWORK = 
    ‘DEFAULT_AUTHENTICATION_CLASSES‘: (
        ‘rest_framework.authentication.SessionAuthentication‘,  # session认证
        ‘rest_framework.authentication.BasicAuthentication‘,   # 基本认证
    )


# 在项目settings.py中配置
REST_FRAMEWORK=
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.TokenAuth",]

也可以在每个视图类中通过设置authentication_classess属性来设置局部使用

from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.views import APIView

class ExampleView(APIView):
    # 类属性
    authentication_classes = [TokenAuth,]
    ...

禁用全局认证

# 在视图类中
class MyAuthentication(BaseAuthentication):
    authentication_classes = []
    def authenticate(self, request):
        ...

查找顺序:先在视图类中查找----->项目的setting中找----->drf默认配置找

认证失败会有两种可能的返回值:

  • 401 Unauthorized 未认证
  • 403 Permission Denied 权限被禁止

二 权限Permissions

权限组件:校验用户权限 - 必须登录、所有用户、登录读写游客只读、自定义用户角色
认证通过:可以进入下一步校验(频率认证)
认证失败:抛出异常,返回403权限异常结果

权限控制可以限制用户对于视图的访问和对于具体数据对象的访问。

  • 在执行视图的dispatch()方法前,会先进行视图访问权限的判断
  • 在通过get_object()获取具体对象时,会进行模型对象访问权限的判断

源码分析

# APIView---->dispatch---->initial--->self.check_permissions(request)(APIView的对象方法)
def check_permissions(self, request):
    # 遍历权限对象列表得到一个个权限对象(权限器),进行权限认证
    for permission in self.get_permissions():
        # 权限类一定有一个has_permission权限方法,用来做权限认证的
        # 参数:权限对象self、请求对象request、视图类对象
        # 返回值:有权限返回True,无权限返回False
        if not permission.has_permission(request, self):
            self.permission_denied(
                request, message=getattr(permission, ‘message‘, None)
            )

使用

# 写一个类,继承BasePermission,重写has_permission,如果权限通过,就返回True,不通过就返回False
from rest_framework.permissions import BasePermission

class UserPermission(BasePermission):
    def  has_permission(self, request, view):
        # 不是超级用户,不能访问
        # 由于认证已经过了,request内就有user对象了,当前登录用户
        user=request.user  # 当前登录用户
        # 如果该字段用了choice,通过get_字段名_display()就能取出choice后面的中文
        print(user.get_user_type_display())
        if user.user_type==1:
            return True
        else:
            return False

可以在配置文件中全局设置默认的权限管理类

REST_FRAMEWORK=
    ...
    "DEFAULT_PERMISSION_CLASSES":["app01.permissions.UserPermission",]

也可以在具体的视图中通过permission_classes属性来设置


from rest_framework.views import APIView

class TestView(APIView):
    permission_classes = (UserPermission,)
    ...

局部禁用

class TestView(APIView):
    permission_classes = []
    ...

内置提供的权限

需要和django自带的auth_user表连用

  • AllowAny 允许所有用户
  • IsAuthenticated 仅通过认证的用户
  • IsAdminUser 仅管理员用户
  • IsAuthenticatedOrReadOnly 已经登陆认证的用户可以对数据进行增删改操作,没有登陆认证的只能查看数据。

可以在配置文件中全局设置默认的权限管理类

REST_FRAMEWORK = 
    ....
    
    ‘DEFAULT_PERMISSION_CLASSES‘: (
        ‘rest_framework.permissions.IsAuthenticated‘,
    )

如果未指明,则采用如下默认配置

‘DEFAULT_PERMISSION_CLASSES‘: (
   ‘rest_framework.permissions.AllowAny‘,
)

也可以在具体的视图中通过permission_classes属性来设置

from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView

class ExampleView(APIView):
    permission_classes = (IsAuthenticated,)
    ...

举例

# 创建超级用户,登陆到admin,创建普通用户(注意设置职员状态,也就是能登陆)

# 全局配置IsAuthenticated
# setting.py
‘DEFAULT_PERMISSION_CLASSES‘: (
        ‘rest_framework.permissions.IsAuthenticated‘,
    )
    
# urls.py
 path(‘test/‘, views.TestView.as_view()),
 
# views.py
class TestView(APIView):
    def get(self,request):
        return Response(‘msg‘:‘个人中心‘)
# 登陆到admin后台后,直接访问可以,如果没登陆,不能访问

##注意:如果全局配置了
rest_framework.permissions.IsAdminUser
# 就只有管理员能访问,普通用户访问不了

自定义权限

如需自定义权限,需继承rest_framework.permissions.BasePermission父类,并实现以下两个任何一个方法或全部

  • .has_permission(self, request, view)

    是否可以访问视图, view表示当前视图对象

  • .has_object_permission(self, request, view, obj)

    是否可以访问数据对象, view表示当前视图, obj为数据对象

例如:

在当前子应用下,创建一个权限文件permissions.py中声明自定义权限类:

from rest_framework.permissions import BasePermission

class IsXiaoMingPermission(BasePermission):
    def has_permission(self, request, view):
        if( request.user.username == "xiaoming" ):
            return True
from .permissions import IsXiaoMingPermission
class StudentViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
    permission_classes = [IsXiaoMingPermission]

三 限流Throttling

频率组件:限制视图接口被访问的频率次数 - 限制的条件(IP、id、唯一键)、频率周期时间(s、m、h)、频率的次数(3/s)
没有达到限次:正常访问接口
达到限次:限制时间内不能访问,限制时间达到后,可以重新访问

可以对接口访问的频次进行限制,以减轻服务器压力。

一般用于付费购买次数,投票等场景使用.

使用

可以在配置文件中,使用DEFAULT_THROTTLE_CLASSESDEFAULT_THROTTLE_RATES进行全局配置

REST_FRAMEWORK = 
    ‘DEFAULT_THROTTLE_CLASSES‘: (
        ‘rest_framework.throttling.AnonRateThrottle‘,
        ‘rest_framework.throttling.UserRateThrottle‘
    ),
    ‘DEFAULT_THROTTLE_RATES‘: 
        ‘anon‘: ‘100/day‘,
        ‘user‘: ‘1000/day‘
    

DEFAULT_THROTTLE_RATES 可以使用 second, minute, hourday来指明周期。

也可以在具体视图中通过throttle_classess属性来配置

from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView

class ExampleView(APIView):
    throttle_classes = (UserRateThrottle,)
    ...

实列

# 内置的频率限制(限制未登录用户)

# 全局使用  限制未登录用户1分钟访问5次
REST_FRAMEWORK = 
    ‘DEFAULT_THROTTLE_CLASSES‘: (
        ‘rest_framework.throttling.AnonRateThrottle‘,
    ),
    ‘DEFAULT_THROTTLE_RATES‘: 
        ‘anon‘: ‘3/m‘,
    


## views.py
from rest_framework.permissions import IsAdminUser
from rest_framework.authentication import SessionAuthentication,BasicAuthentication
class TestView1(APIView):
    authentication_classes=[]
    permission_classes = []
    def get(self,request,*args,**kwargs):
        return Response(‘我是未登录用户‘)


# 局部使用
from rest_framework.permissions import IsAdminUser
from rest_framework.authentication import SessionAuthentication,BasicAuthentication
from rest_framework.throttling import AnonRateThrottle
class TestView2(APIView):
    authentication_classes=[]
    permission_classes = []
    throttle_classes = [AnonRateThrottle]
    def get(self,request,*args,**kwargs):
        return Response(‘我是未登录用户‘)

可选限流类

1) AnonRateThrottle

限制所有匿名未认证用户,使用IP区分用户。

使用DEFAULT_THROTTLE_RATES[‘anon‘] 来设置频次

2)UserRateThrottle

限制认证用户,使用User id 来区分。

使用DEFAULT_THROTTLE_RATES[‘user‘] 来设置频次

3)ScopedRateThrottle

限制用户对于每个视图的访问频次,使用ip或user id。

例如:

class ContactListView(APIView):
    throttle_scope = ‘contacts‘
    ...

class ContactDetailView(APIView):
    throttle_scope = ‘contacts‘
    ...

class UploadView(APIView):
    throttle_scope = ‘uploads‘
    ...
REST_FRAMEWORK = 
    ‘DEFAULT_THROTTLE_CLASSES‘: (
        ‘rest_framework.throttling.ScopedRateThrottle‘,
    ),
    ‘DEFAULT_THROTTLE_RATES‘: 
        ‘contacts‘: ‘1000/day‘,
        ‘uploads‘: ‘20/day‘
    

实例

全局配置中设置访问频率

    ‘DEFAULT_THROTTLE_RATES‘: 
        ‘anon‘: ‘3/minute‘,
        ‘user‘: ‘10/minute‘
    
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.generics import RetrieveAPIView
from rest_framework.throttling import UserRateThrottle

class StudentAPIView(RetrieveAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
    authentication_classes = [SessionAuthentication]
    permission_classes = [IsAuthenticated]
    throttle_classes = (UserRateThrottle,)

自定义频率类

# 自定义的逻辑
#(1)取出访问者ip
#(2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走
#(3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
#(4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
#(5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
class MyThrottles():
    VISIT_RECORD = 
    def __init__(self):
        self.history=None
    def allow_request(self,request, view):
        #(1)取出访问者ip
        # print(request.META)
        ip=request.META.get(‘REMOTE_ADDR‘)
        import time
        ctime=time.time()
        # (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问
        if ip not in self.VISIT_RECORD:
            self.VISIT_RECORD[ip]=[ctime,]
            return True
        self.history=self.VISIT_RECORD.get(ip)
        # (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
        while self.history and ctime-self.history[-1]>60:
            self.history.pop()
        # (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
        # (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
        if len(self.history)<3:
            self.history.insert(0,ctime)
            return True
        else:
            return False
    def wait(self):
        import time
        ctime=time.time()
        return 60-(ctime-self.history[-1])

全局使用

REST_FRAMEWORK = 
    ‘DEFAULT_THROTTLE_CLASSES‘:[‘app01.utils.MyThrottles‘,],

局部使用

#在视图类里使用
throttle_classes = [MyThrottles,]







drf-认证权限频率过滤排序分页(代码片段)

1.认证组件1.1局部认证1.首先写两个接口,一个查询单个一个查询所有,我们利用视图扩展类和视图子类写在一个视图类上:views.py:fromrest_framework.viewsetsimportViewSetMixinfromrest_framework.genericsimportListAPIViewfromrest_framework.mixinsimportRetrieveMo... 查看详情

drf08(代码片段)

目录三大认证流程认证组件权限组件频率组件自定义token的签发三大认证流程由于DRF中,所有的视图类都要直接和间接继承APIView类,也只有APIView类中才有dispatch方法,所以所有的请求都要经过三大认证,认证通过后执行相应请求的视... 查看详情

drf权限频率(代码片段)

...都有哪些方法~~权限组件源码我们之前说过了DRF的版本和认证~也知道了权限和频率跟版本认证都是在initial方法里初始化的~~其实我们版本,认证,权限,频率控制走的源码流程大致相同~~大家也可以在源码里看到~~我们的权限类... 查看详情

drf权限频率(代码片段)

...都有哪些方法~~权限组件源码我们之前说过了DRF的版本和认证~也知道了权限和频率跟版本认证都是在initial方法里初始化的~~其实我们版本,认证,权限,频率控制走的源码流程大致相同~~大家也可以在源码里看到~~我们的权限类... 查看详情

drf权限频率(代码片段)

...初始化这些组件的时候也是有顺序的版本在前面~然后是认证,然后是权限~最后是频率所以大家要清楚我们的权限执行的时候~我们的认证已经执行结束了前提在model中的UserInfo表中加了一个字段~用户类型的字段做好数据迁移~~1.定... 查看详情

drf权限的流程(代码片段)

...然后依次--->>封装请求--->>处理版本--->>>认证--->>>权限--->>>限制访问频率(1)auth需要通过token唯一标识来认证(2)通过auth认证后得到,用户user信息,但是没有admin的权限权限用来做进一步做职责的 查看详情

drf认证--2019-08-0818:02:57(代码片段)

目录认证组件的详细用法原文:http://106.13.73.98/__/65/本文详细讲述了DRF认证组件的原理以及用法.@*源码剖析**上一篇博客讲解DRF版本的时候我们都知道了,在dispatch方法里执行了initial方法来初始化我们的版本.而在initial方法里有我... 查看详情

认证权限频率自定义签发token-多方式登录(代码片段)

目录三大认证流程图路由配置认证组件权限组件自定义权限类配置drf自带的权限类drf-jwt签发token源码分析多方式登录签发tokenVIP用户认证权限例子频率组件自定义频率类三大认证流程图路由配置在应用下新建文件router.py#router.pyfro... 查看详情

79-drf三大认证的配置及使用方法(代码片段)

目录三大认证一、身份认证1、身份认证配置2、drf提供的身份认证类(了解)3、rf-jwt提供的身份认证类(常用)4、自定义身份认证类(需要自定义签发token时用)5、自定义签发token及多方式登陆二、权限认证1、权限认证配置2、drf提供的... 查看详情

drf--认证,权限,限制(代码片段)

 认证、权限和限制身份验证是将传入请求与一组标识凭据(例如请求来自的用户或其签名的令牌)相关联的机制。然后权限和限制组件决定是否拒绝这个请求。简单来说就是:认证确定了你是谁权限确定你能不能访问某个接... 查看详情

drf认证权限限制(代码片段)

 认证前提表定义一个用户表和一个保存用户Token的表:classUserInfo(models.Model):username=models.CharField(max_length=16)password=models.CharField(max_length=32)type=models.SmallIntegerField(choices=((1,‘普通用户‘),(2,‘VIP用户 查看详情

drf--频率组件jwt使用(代码片段)

...uest,*args,**kwargs)点进去#2)self.check_throttles(request)进行频率认证#频率组件核心源码分析defcheck_throttles(self,request):throttle_durations=[]#1)遍历配置的频率认证类,初始化得到一个个频率认证类对象(会调用频率认证类的__init__()方法)#2... 查看详情

频率类组件-认证规图分析-jwt认证-drf-jwt插件(代码片段)

...uest,*args,**kwargs)点进去#2)self.check_throttles(request)进行频率认证频率组件原理分析 频率组件的核心源码分析defcheck_throttles(self,request):throttle_durations=[]#1)遍历配置的频率认证类,初始化得到一个个频率认证类对象(会调用频率... 查看详情

drf权限和频率限制(代码片段)

权限viewsfromrest_framework.permissionsimportBasePermissionfromrest_frameworkimportexceptions#权限类操作classMyPermission(BasePermission):#也是一种报错,返回给前端message='code':10001,'error':'你没权限'defhas_permission(self,request,view):""&q... 查看详情

drf的权限和频率

DRF的权限权限组件源码权限和频率以及版本认证都是在initial方法里初始化的我们的权限类一定要有has_permission方法~否则就会抛出异常~~这也是框架给我提供的钩子~~ 在rest_framework.permissions这个文件中~存放了框架给我们提供的... 查看详情

drf框架8系统权限类使用用户中心信息自查token刷新机制认证组件项目使用:多方式登录权限组件项目使用:vip用户权限频率组件异常组件项目使用(代码片段)

系统权限类使用图书接口:游客只读,用户可增删改查权限使用fromrest_framework.permissionsimportIsAuthenticatedOrReadOnlyclassBookViewSet(ModelViewSet):#游客只读,用户可增删改查permission_classes=[IsAuthenticatedOrReadOnly]queryset=models.Book.objects.all()seriali... 查看详情

drf框架(代码片段)

...前台;将前台的数据反序列化成后台model对象再入库三大认证组件:认证组件、权限组件(RBAC)、频率组件视图家族:View一系列组件五、群查接口相关组件:搜索、筛选、排序、分页DRF学习目的:必须掌握六大基础接口:单查、群... 查看详情

drf的认证(代码片段)

一、概述认证是将传入请求与一组标识凭据(例如请求来自的用户或其签名的令牌)相关联的机制。然后权限和限制组件决定是否拒绝这个请求。简单来说就是:认证确定了你是谁权限确定你能不能访问某个接口限制确定你访问... 查看详情