首页 > 其他 > 详细

四:认证、权限、频率组件使用

时间:2020-03-22 20:43:40      阅读:42      评论:0      收藏:0      [点我收藏+]

一、认证

认证涉及登录,登录为一次post请求,则涉及跨站请求伪造,django中间件csrf很好的解决了这个问题,但是在前后端分离开发的过程中,使用Postman发送请求无法使用该组件,所以将该中间件注释后,自己简单实现一个类似csrftoken的功能:

  登录后需要验证token值,每次登录,token值都会变。登录后,所有请求必须带着token值才能通过验证

import hashlib
import time
# 利用摘要算法生成一条token值,采用加盐方式
class GetToken(object):

    def __init__(self, username):
        self.username = username

    def get_md5_token(self):
        md = hashlib.md5(bytes(self.username, encoding="utf-8"))
        md.update(bytes(str(time.time()), encoding="utf-8"))
        return md.hexdigest()

# 登录视图
class LoginView(APIView):
    def post(self, request):
        username = request.data.get(username)
        password = request.data.get(password)
        obj = models.User.objects.filter(username=username, password=password).first()
        res = {"state": 200, "msg": None}
        if obj:
            token = GetToken(obj.username)
            str_token = token.get_md5_token()
            models.Token.objects.update_or_create(user=obj, defaults={"token": str_token})
            res["token"] = str_token
        else:
            res["state"] = 404
            res["msg"] = "登录失败"
        return Response(res)

  认证类:

from app01 import models
from rest_framework import exceptions

# 认证类
class Authentication(object):

    def authenticate(self, request):
        token = request.GET.get(token)
        obj = models.Token.objects.filter(token=token).first()
        if obj:
            return obj.user.username, obj.token
        else:
            raise exceptions.AuthenticationFailed(验证失败)

    # 不加这个方法会报错
    def authenticate_header(self, request):
        pass

  为其它视图添加认证组件:

from rest_framework import viewsets
from app01 import utils

class BookView(viewsets.ModelViewSet):
    authentication_classes = [utils.Authentication, ]  # 认证组件,一个列表,类别中放认证类
    queryset = models.Book.objects.all()
    serializer_class = serializers.BookSerializers

  全局视图添加认证类,需要在settings中配置:

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

  如果添加了全局,某个视图不许要认证,只需要在视图中设置为空即可:

authentication_classes = []

 

2、权限

  一条url代表一条权限,所有权限类验证时,应该是取到用户所有的url后,根据访问的地址进行验证,这里就不详细示例:

class User(models.Model):
    username = models.CharField(max_length=48)
    password = models.CharField(max_length=64)
    roles_choices = ((1, "普通用户"), (2, "管理员"), (3, "超级管理员"))
    role = models.IntegerField(choices=roles_choices, default=1)

    def __str__(self):
        return self.username
# 权限类
class PermissionCheck(object):
    message = "你不是超级管理员"
    # 这里的request属于APIview重新构造的reuqest,经过认证后,认证组件返回一个request.user和request.auth,
    # 这两个的返回结果在自己的认证类中自定义返回的结果,所以这里能够直接调用
    def has_permission(self, request, view):
        if request.user.role == 3:
            return True
        else:
            return False
class BookView(viewsets.ModelViewSet):
    authentication_classes = [utils.Authentication, ]  # 认证组件,一个列表,类别中放认证类
    permission_classes = [utils.PermissionCheck, ]  # 权限组件, 一个列表, 列表中放权限类
    queryset = models.Book.objects.all()
    serializer_class = serializers.BookSerializers

  全局视图加入权限验证需要在settings中配置:

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.utils.Authentication",], # 认证
    "DEFAULT_PERMISSION_CLASSES":["app01.utils.PermissionCheck",] # 权限
}

 

3、频率

  rest_framework提供内置throttle类,继承BaseThrottle

# 频率
from rest_framework.throttling import BaseThrottle

VISIT_RECORD = {}


class VisitThrottle(BaseThrottle):

    def __init__(self):
        self.history = None

    def allow_request(self, request, view):
        remote_addr = request.META.get(REMOTE_ADDR)
        print(remote_addr)
        import time
        ctime = time.time()

        if remote_addr not in VISIT_RECORD:
            VISIT_RECORD[remote_addr] = [ctime, ]
            return True

        history = VISIT_RECORD.get(remote_addr)
        self.history = history

        while history and history[-1] < ctime - 60:
            history.pop()

        if len(history) < 3:
            history.insert(0, ctime)
            return True
        else:
            return False

    def wait(self):
        import time
        ctime = time.time()
        return 60 - (ctime - self.history[-1])
from rest_framework import viewsets
from app01 import utils

class BookView(viewsets.ModelViewSet):
    authentication_classes = [utils.Authentication, ]  # 认证组件,一个列表,类别中放认证类
    permission_classes = [utils.PermissionCheck, ]  # 权限组件, 一个列表, 列表中放权限类
    throttle_classes = [utils.VisitThrottle, ]   # 频率组件
    queryset = models.Book.objects.all()
    serializer_class = serializers.BookSerializers

  全局视图设置频率:

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.utils.Authentication",], # 认证
    "DEFAULT_PERMISSION_CLASSES":["app01.utils.PermissionCheck",], # 权限
"DEFAULT_THROTTLE_CLASSES":["app01utils.VisitThrottle",]  # 频率
}

  内置throttle类实现:继承SimpleRateThrottle

class VisitThrottle(SimpleRateThrottle):

    scope="visit_rate"
    def get_cache_key(self, request, view):

        return self.get_ident(request)

  需要在settings中设置:

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.utils.Authentication",], # 认证
    "DEFAULT_PERMISSION_CLASSES":["app01.utils.PermissionCheck",], # 权限
    "DEFAULT_THROTTLE_CLASSES":["app01utils.VisitThrottle",],  # 频率
    "DEFAULT_THROTTLE_RATES":{
        "visit_rate":"5/m",
    }
}

 

四:认证、权限、频率组件使用

原文:https://www.cnblogs.com/aizhinong/p/12547975.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!