drf-认证权限频率

drf-认证权限频率

  • 认证Authentication

    • 编写models
  • 新建认证类

    • 编写视图
  • 编写路由

  • 认证类完成的步骤

  • 权限Permissions

  • 限流Throttling

认证Authentication

编写models

1.编写用户表
class User(models.Model):
    username = models.CharField(max_lengh = 32)
    password = models.CharField(max_length=32)
     def __str__(self):
        return self.username    

2.编写用户登录记录表
	class UserToken(models.Model):
    user = models.OneToOneField(to='User', on_delete=models.CASCADE)
    token = models.CharField(max_length=32, null=True) 
    # 用户如果没有登录,就是空,如果登录了,就有值,登录多次以最后一次为准

新建认证类

from .models import UserToken
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed


class LoginAuth(BaseAuthentication):
    def authenticate(self, request):
        # 在这里做认证,校验用户是否登录(带了token,并且能查到,就是登录,返回两个值,否则就是没登录,抛异常)
        # 用户带的token从哪取?后端人员定的:放在请求地址中
        token = request.GET.get('token')
        # 通过token查询该token是否是在表中有记录
        user_token = UserToken.objects.filter(token=token).first()
        if user_token:
            return user_token.user, token  # 返回两个值,一个是当前登录用户,一个是token
        else:
            raise AuthenticationFailed('您没有登录')

编写视图

class UserView(ViewSet):
    authentication_classes = []
    @action(methods=['POST', ], detail=False, url_path='login')
    def login(self, request):
        # 取出前端传入的用户名密码,校验,通过,返回登录成功,失败就返回用户名密码错误
        username = request.data.get('username')
        password = request.data.get('password')
        user = User.objects.filter(username=username, password=password).first()
        if user:
            # 登录成功,不同人生成的token是不一样的,谁登录的,就把token存到UserToken表中
            token = str(uuid.uuid4())  # 生成一个永不重复的随机字符串
            # 存UserToken:如果没有记录,就是新增,如果有记录更新一下即可
            # 通过user去UserToken表中查数据,如果能查到,使用defaults的数据更新,如果查不到,直接通过user和defaults的数据新增
            UserToken.objects.update_or_create(defaults={'token': token}, user=user)
            return Response({'code': 100, 'msg': '登录成功', 'token': token})
        else:
            return Response({'code': 101, 'msg': '用户名或密码错误'})
  • uuid的作用

    生成一个永不重复的随机字符串,多用于认证

路由层

from rest_framework.routers import SimpleRouter, DefaultRouter

router = SimpleRouter()

router.register('user',views.UserView,'user')

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include(router.urls)),
]

认证类

  • 认证类的步骤

    ①写一个认证类,继承BaseAuthentication

    ②重写authenticate方法,在内部做认证

    ③如果认证通过,返回2个值(用户名和 用户认证后的随机字符串)

    ④认证不通过抛AuthenticationFailed异常

    ⑤ 只要返回了两个值,在后续的request.user 就是当前登录用户

    ⑥让某个视图类登录后才能访问

    • 让某个视图类登录后才能访问有两种方式

      方式一:

      class BookView(ModelViewSet):
          authentication_classes = [LoginAuth,]
      

      方式二:

      • 全局配置(settings中)

        REST_FRAMEWORK={
                    'DEFAULT_AUTHENTICATION_CLASSES':['app01.auth.LoginAuth',]
                }
        
      • 局部禁用

        authentication_classes = []
        

        先走自身的authentication_classes

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

    ​ 1.401——> Unauthorized 未认证

    ​ 2.403——> Permission Denied 权限被禁止

内置的认证类

内置的认证中的类

  • BasicAuthentication

    ​ BasicAuthentication 是 基本认证

  • RemoteUserAuthentication

    ​ RemoteUserAuthentication 是 跟用户登录相关的

  • SessionAuthentication

    ​ SessionAuthentication是session认证

    • 详情

      1.如果前端带着cookie过来,经过session的中间件,如果登录了,在request.user中就有当前登录用户

      2.drf没有限制是否登录

      3.加了这个认证,如果没有登录,就不允许往后访问了

  • TokenAuthentication

    ​ TokenAuthentication认证是 jwt认证

权限Permissions

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

权限使用的步骤

①写一个类,继承BasePermission

②重写has_permission方法

③在方法中校验用户是否有权限(request.user就是当前登录用户)

④如果有权限,返回True,没有权限,返回False

⑤self.message 是给前端的提示信息

⑥通过权限判定查看用户是否有权限查看该视图

  • 有两种方式
    • 局部使用

      # 局部使用只需要在视图类里加入:
      permission_classes = [UserTypePermission,]
      
    • 全局使用,局部禁用

      settings:
      REST_FRAMEWORK={
          "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
          "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.UserTypePermission",]
      }
      view:
          在视图函数中加入
          permission_classes = [ ]
      

编写权限类

from rest_framework.permissions import BasePermission
class UserTypePermission(BasePermission):
    def has_permission(self, request, view):
        # 只有超级管理员有权限
        if request.user.user_type == 1:
            return True  # 有权限
        else:
            # self.message = '普通用户和2b用户都没有权限' # 返回给前端的提示是什么样
            # 使用了choice后,user.user_type 拿到的是数字类型,想变成字符串 user.get_user_type_display()
            # self.message = '您是:%s 用户,您没有权限'%request.user.get_user_type_display()
            return False  # 没有权限

内置的权限类

内置的认证中的类

  • BasePermission

    所有的基类

  • AllowAny

    ​ 允许所有通过权限

  • IsAuthenticated

    ​ 判断是否登录,只有登录后才有权限进入

    ​ 认证类,如果登录了,返回(当前登录用户,None), 如果没有登录返回 None

  • IsAdminUser

    判断用户是否是超级管理员即auth的user表中is_staff字段是否为True

    is_staff字段是指对后台管理有没有权限

限流Throttling

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

通常是利用用户的id或者 IP地址来进行限流

频率类的使用步骤

①写一个类:继承SimpleRateThrottle

②重写get_cache_key,返回唯一的字符串,会以这个字符串做频率限制

③写一个类属性scop='随意写',必须要跟配置文件对象

④配置文件 settings 中写配置文件

 'DEFAULT_THROTTLE_RATES': {
        '随意写': '3/m'  # 3/h  3/s  3/d
    	}

⑤通过频率类的判定,管理用户是否能继续查看

  • 有两种方式

    • 局部配置

      #在视图类里使用
      throttle_classes = [MyThrottles,]
      
      
    • 全局配置,局部禁用

      settings:
          REST_FRAMEWORK = {
          'DEFAULT_THROTTLE_CLASSES':['app01.utils.MyThrottles',],
           'DEFAULT_THROTTLE_RATES': {
              'luffy': '3/m'
          }    
      }
          
      view:
          throttle_classes = [ ]
      

频率类编写

from rest_framework.throttling import BaseThrottle, SimpleRateThrottle
class MyThrottling(SimpleRateThrottle):  # 我们继承SimpleRateThrottle去写,而不是继承BaseThrottle去写
    # 类属性,这个类属性可以随意命名,但要跟配置文件对应
    scope = 'luffy'
    def get_cache_key(self, request, view):
        # 返回什么,频率就以什么做限制
        # 可以通过用户id限制
        # 可以通过ip地址限制
        return request.META.get('REMOTE_ADDR')

内置的频率类

内置的频率的类

  • BaseThrottle

    指所有的基类

  • SimpleRateThrottle

    ​ 所写的频率类全继承这个类,少写了代码

  • AnonRateThrottle

    ​ 按ip地址限制

    ​ 在配置文件中配置

     'DEFAULT_THROTTLE_RATES': {
            'anon': '3/m',
        	}
    
  • UserRateThrottle

    ​ 按用户id限制

    在配置文件中配置

    'DEFAULT_THROTTLE_RATES': {
        'user': '3/m',
    }
    

自定义频率类

from rest_framework.throttling import BaseThrottle
class MyThrottle(BaseThrottle):
    VISIT_RECORD = {}  # 存放用户访问记录{ip1:[时间1,时间2],ip2:[时间1,时间2],'192.168.1.101':[当前时间,]}

    def __init__(self):
        self.history = None
    def allow_request(self, request, view):
        # 在这里写逻辑:根据ip地址判断用户是不是超过了频率限制
        # (1)取出访问者ip
        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) # 当前访问者的时间列表 [时间2,]
        # (3)循环判断当前ip的时间列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
        while self.history and -ctime + self.history[-1] < 60: #循环结束后,剩下的都是1分钟以后访问的时间
            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])

其他

1) AnonRateThrottle

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

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

2)UserRateThrottle

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

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

3)ScopedRateThrottle

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

posted @   Nirvana*  阅读(36)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
点击右上角即可分享
微信分享提示