DRF 认证、权限、限制

认证:

  定义一个用户表和一个保存用户的Token表

# ======================day96=======================

class UserInfo(models.Model):
    username = models.CharField(max_length=16,unique=True)
    password = models.CharField(max_length=32)

    type = models.SmallIntegerField(
        choices=((1,"普通用户"),(2,"VIP用户")),
        default=1
    )

class Token(models.Model):
    token = models.CharField(max_length=128)
    user = models.OneToOneField(to="UserInfo",on_delete=models.CASCADE)

  定义一个登陆视图:

# 生成Token的函数
def get_token_code(username):
    """
    根据用户名和时间戳来生成永不相同的token随机字符串
    :param username: 字符串格式的用户名
    :return: 字符串格式的Token
    """

    import time
    import hashlib

    timestamp = str(time.time())
    m = hashlib.md5(username.encode("utf-8"))
    # md5 要传入字节类型的数据
    m.update(timestamp.encode("utf-8"))
    return m.hexdigest()  # 将生成的随机字符串返回

# 登陆视图

class LoginView(APIView):
    '''
    登陆检测试图。
    1,接收用户发过来的用户名和密码数据
    2,校验用户密码是否正确
        - 成功就返回登陆成功,然后发Token
        - 失败就返回错误提示
    '''

    def post(self,request):
        res = {"code":0}
        # 从post 里面取数据
        print(request.data)
        username = request.data.get("username")
        password = request.data.get("password")
        # 去数据库查询
        user_obj = models.UserInfo.objects.filter(
            username = username,
            password = password
        ).first()
        if user_obj:
            # 登陆成功
            # 生成Token
            token = get_token_code(username)
            # 将token保存
            # 用user = user_obj 这个条件去Token表里查询。
            # 如果又记录就更新default里传的参数,没有记录就用default里传的参数创建一条数据。
            models.Token.objects.update_or_create(defaults={"token":token},user = user_obj)
            # 将token返回给用户
            res["token"] = token
        else:
            # 登陆失败
            res["code"] = 1
            res["error"] = "用户名或密码错误"
        return Response(res)

新建一个utils文件夹 下面放一些组件:

  定义一个MyAuth认证类:

"""
这里放自定义的认证类
"""
from rest_framework.authentication import BaseAuthentication
from app01 import models
from rest_framework.exceptions import AuthenticationFailed


class MyAuth(BaseAuthentication):

    def authenticate(self, request):
        # print(request.method)
        if request.method in ["POST","PUT","DELETE"]:
            # 如果请求是post,put,delete三种类型时
            # 获取随用户请求发来的token随机码
            token = request.data.get("token")
            # 然后去数据库查询有没有这个token
            token_obj = models.Token.objects.filter(token=token).first()
            if token_obj:
                # 如果存在,则说明验证通过,以元组形式返回用户对象和token
                return token_obj.user,token
            else:
                # 不存在就直接抛错
                raise AuthenticationFailed("无效的token")
        else:
        # 这一步的else 是为了当用户是get请求时也可获取数据,并不需要验证token.
            return None,None

视图级别认证:

class CommentViewSet(ModelViewSet):
    queryset = models.Comment.objects.all()
    serializer_class = app01_serializers.CommentSerializer
    authentication_classes = [MyAuth,]
    permission_classes = [MyPermission,]

全局级别认证:需要在settings.py文件设置:

# REST FRAMEWORK 相关的配置

REST_FRAMEWORK = {
    # 关于认证的全局配置
    # "DEFAULT_AUTHENTICATION_CALSSES": ["app01.utils.auth.MyAuth",],
    # "DEFAULT_PERMISSION_CLASSES" : ["app01.utils.permission.MyPermission"],
    # "DEFAULT_THROTTLE_CLASSES" : ["app01.utils.throttle.MyThrottle",],
    "DEFAULT_THROTTLE_CLASSES" : ["app01.utils.throttle.VisitThrottle",],
    "DEFAULT_THROTTLE_RATES":{
        "XXX":"5/m",
    }
}

权限:

  只有VIP用户才能看的内容:

  自定义权限类:

'''
自定义的权限类
'''

from rest_framework.permissions import BasePermission

class MyPermission(BasePermission):
    message = "sorry,您没有权限"
    def has_permission(self, request, view):
        # 内置封装的方法
        '''
        判断该用户有没有权限
        '''
        # 判断用户是不是VIP用户
        # 如果是VIP用户就返回True
        # 如果是普通用户就返会Flase

        if request.method in ["POST","PUT","DELETE"]:
            # print(111)
            print(request.user.username)
            print(request.user.type)
            print(type(request.user.type))
            if request.user.type == 2:   # 是VIP用户
                print(2222)
                return True
            else:
                return False
        else:
            return True

    def has_object_permission(self, request, view, obj):
        # 用来判断针对的obj权限:
        # 例如:是不是某一个人的评论
        '''
        只有评论人是自己才能删除选定的评论
        '''
        if request.method in ["PUT","DELETE"]:
            print(obj.user.username)
            print(request.user.username)
            if obj.user == request.user:
                # 表示当前评论对象的用户就是登陆用户
                return True
            else:
                return False
        else:
            return True

视图级别配置:

class CommentViewSet(ModelViewSet):
    queryset = models.Comment.objects.all()
    serializer_class = app01_serializers.CommentSerializer
    authentication_classes = [MyAuth,]
    permission_classes = [MyPermission,]

全局级别配置:

# REST FRAMEWORK 相关的配置

REST_FRAMEWORK = {
    # 关于认证的全局配置
    # "DEFAULT_AUTHENTICATION_CALSSES": ["app01.utils.auth.MyAuth",],
    # "DEFAULT_PERMISSION_CLASSES" : ["app01.utils.permission.MyPermission"],
    # "DEFAULT_THROTTLE_CLASSES" : ["app01.utils.throttle.MyThrottle",],
    "DEFAULT_THROTTLE_CLASSES" : ["app01.utils.throttle.VisitThrottle",],
    "DEFAULT_THROTTLE_RATES":{
        "XXX":"5/m",
    }
}

限制:

  自定义限制类:

'''
自定义的访问限制类
'''

from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
import time

# =============================
# DIC = {}
#
# class MyThrottle(BaseThrottle):
#     def allow_request(self, request, view):
#         '''
#         返回True就放行,返回False表示被限制了
#         '''
#
#         # 获取当前访问的ip地址
#         ip = request.META.get("REMOTE_ADDR")
#
#         # 获取当前时间
#         now = time.time()
#
#         # 判断当前ip是否有访问记录
#         if ip not in DIC:
#             DIC[ip] = []    # 如果没有访问记录初始化一个空的访问历史列表
#
#         # 高端操作
#         history = DIC[ip]
#         # 当当前ip存在访问记录,且现在的访问时间比最初的一次访问时间大于10秒
#         while history and now - history[-1] > 10:
#             history.pop()   # 删掉历史列表中的最后一个记录
#         # 判断最近一分钟的访问次数是否超过了阈值(3次)
#         if len(history)>=3:
#             return False
#         else:
#             # 把这一次的访问时间加到访问历史列表的第一位
#             DIC[ip].insert(0,now)
#             return True


# ==============================
# 以上代码等同于一下代码
class VisitThrottle(SimpleRateThrottle):
    scope = 'XXX'

    def get_cache_key(self, request, view):
        return self.get_ident(request)   # 求当前访问的IP

视图级别:

from app01.utils.auth import MyAuth
from app01.utils.permission import MyPermission
from app01.utils.throttle import SimpleRateThrottle
# from app01.utils.throttle import
class CommentViewSet(ModelViewSet):
    queryset = models.Comment.objects.all()
    serializer_class = app01_serializers.CommentSerializer
    authentication_classes = [MyAuth,]
    permission_classes = [MyPermission,]

全局级别:

# REST FRAMEWORK 相关的配置

REST_FRAMEWORK = {
    # 关于认证的全局配置
    # "DEFAULT_AUTHENTICATION_CALSSES": ["app01.utils.auth.MyAuth",],
    # "DEFAULT_PERMISSION_CLASSES" : ["app01.utils.permission.MyPermission"],
    # "DEFAULT_THROTTLE_CLASSES" : ["app01.utils.throttle.MyThrottle",],
    "DEFAULT_THROTTLE_CLASSES" : ["app01.utils.throttle.VisitThrottle",],
    "DEFAULT_THROTTLE_RATES":{
        "XXX":"5/m",
    }
}
原文地址:https://www.cnblogs.com/stfei/p/9416652.html