restful(3):认证、权限、频率

models.py中:

class UserInfo(models.Model):
    name = models.CharField(max_length=32)
    psw = models.CharField(max_length=32)
    user_type_choices = ((1,"普通"),(2,"VIP"),(3,"SVIP"))
    user_type = models.SmallIntegerField(choices=user_type_choices,default=1)  # 新添加一个标识用户权限级别的字段

class Token(models.Model):  # Token类用于 认证
    user = 
models.OneToOneField(to="UserInfo",on_delete=models.CASCADE)
    token = models.CharField(max_length=128)

认证组件:

局部视图认证:

在app01.service.auth.py:

class Authentication(BaseAuthentication):

    def authenticate(self,request):  # authenticate()  这个方法名是固定的
        token=request._request.GET.get("token")
        token_obj=UserToken.objects.filter(token=token).first()
        if not token_obj:  # 检查token是否存在
            raise exceptions.AuthenticationFailed("验证失败!")  # 认证失败时的固定语法
        return (token_obj.user,token_obj)  # 认证成功后需要返回一个元组:第一个是用户有关的信息

在views.py:

def get_random_str(user):
    import hashlib,time
    ctime=str(time.time())

    md5=hashlib.md5(bytes(user,encoding="utf8"))  # user是为了“加盐”处理
    md5.update(bytes(ctime,encoding="utf8"))

    return md5.hexdigest()


from app01.service.auth import *

from django.http import JsonResponse
class LoginViewSet(APIView):
    authentication_classes = [Authentication,]  # authentication_classes 是固定写法;需要认证的类都写在后面的列表中
    def post(self,request,*args,**kwargs):
        res={"code":1000,"msg":None}
        try:
            user=request._request.POST.get("user")  
            pwd=request._request.POST.get("pwd")
            user_obj=UserInfo.objects.filter(user=user,pwd=pwd).first()
            print(user,pwd,user_obj)
            if not user_obj:
                res["code"]=1001
                res["msg"]="用户名或者密码错误"
            else:
                token=get_random_str(user) 
                UserToken.objects.update_or_create(user=user_obj,defaults={"token":token})  # 表中没有就创建,有就更新;# 返回一个元组:第一个是对象,第二个是布尔值(表示create还是update)
                res["token"]=token

        except Exception as e:
            res["code"]=1002
            res["msg"]=e

        return JsonResponse(res,json_dumps_params={"ensure_ascii":False})  # {"ensure_ascii":False} 作用:显示中文

全局视图认证组件:

settings.py配置如下:

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",]  # 写上 认证类的路径
}

权限组件

局部视图权限

在app01.service.permissions.py中:

from rest_framework.permissions import BasePermission
class SVIPPermission(BasePermission):
    message="SVIP才能访问!"  # 没有权限时返回的错误信息
    def has_permission(self, request, view):
        if request.user.user_type==3:
            return True
        return False  

# return True就是通过权限认证, return False 即没有权限

在views.py:

from app01.service.permissions import *

class BookViewSet(generics.ListCreateAPIView):
    permission_classes = [SVIPPermission,]  # permission_classes 是固定写法;需要校验的权限类都写在后面的列表中(这是局部权限校验)
    queryset = Book.objects.all()
    serializer_class = BookSerializers

全局视图权限:

settings.py配置如下:

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",]  # 写上权限认证类的路径
}

throttle(访问频率)组件

局部视图throttle

在app01.service.throttles.py中:

from rest_framework.throttling import BaseThrottle

VISIT_RECORD={}
class VisitThrottle(BaseThrottle):

    def __init__(self):
        self.history=None

    def allow_request(self,request,view):  # allow_request()是固定的方法名

        # 以下为业务逻辑(rest 只处理数据,不处理逻辑)
        remote_addr = request.META.get('REMOTE_ADDR')  # 客户端的IP地址
        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 # return True 表示通过验证
        else:
            return False  # return False 表示没通过验证

    def wait(self):
        import time
        ctime=time.time()
        return 60-(ctime-self.history[-1])

在views.py中:

from app01.service.throttles import *

class BookViewSet(generics.ListCreateAPIView):
    throttle_classes = [VisitThrottle,]  # throttle_classes 是固定写法;
    queryset = Book.objects.all()
    serializer_class = BookSerializers

全局视图throttle

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
    "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",]
}

内置throttle类

在app01.service.throttles.py修改为:

class VisitThrottle(SimpleRateThrottle):

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

        return self.get_ident(request)

settings.py设置:

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
    "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",],
    "DEFAULT_THROTTLE_RATES":{
        "visit_rate":"5/m",
    }
}

猜你喜欢

转载自www.cnblogs.com/neozheng/p/9589175.html