7、认证、权限、频率

一、drf之认证功能类

用户登录后才能访问接口

1、表准备

# 用户表
class User(models.Model):
    name = models.CharField(max_length=16)  # 用户名
    password = models.CharField(max_length=32)  # 密码


# 用户状态表
class UserToken(models.Model):
    user = models.OneToOneField(to=User, on_delete=models.CASCADE)  # 一对一表关系外键
    token = models.CharField(max_length=32)

2、登录功能

# 如果全局使用了认证类,登录接口需要局部禁用掉
class LoginView(ViewSet):
    # 不使用任何认证类(全局配置认证类时,登录功能也要认证,这样不合理,所以这里需要单独禁用认证类)
    authentication_classes = []  
    
    @action(methods=['POST'], detail=False)
    def login(self, request):
        name = request.data.get('name')
        password = request.data.get('password')
        user = User.objects.filter(name=name, password=password).first()
        if user:
            # 生成一个随机字符串
            # 通过伪随机数生成一个永不重复的字符串
            token = str(uuid.uuid4())
            # 把随机字符串存入表,UserToken表,如果存在,就更新token,如果不存在,就新增
            UserToken.objects.update_or_create(defaults={'token': token}, user=user)
            return Response({'code': 100, 'msg': '登录成功', 'token': token})
        else:
            return Response({'code': 101, 'msg': '用户名或密码错误'})

3、认证类编写

# 自定义认证类,要继承BaseAuthentication,重写authenticate,如果认证通过,返回两个值,如果认证失败,抛认证失败的异常,这里我就在应用下新建了一个auth.py文件
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from .models import UserToken


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:
            # 带的token是有效的
            # user_token.user当前登录用户
            return user_token.user, token
        else:
            raise AuthenticationFailed('token不合法或没有迭代token')

4、认证类的使用

# 局部使用(在视图类中加入)

# 认证类的局部配置
from app01.auth import LoginAuth
class PublishView(ModelViewSet):
    # 局部配置,把认证类放入中括号里
    authentication_classes = [LoginAuth,]
    

# 全局使用(在配置文件加入)
# 认证类的全局配置
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": ["app01.auth.LoginAuth", ]
}

二、drf之权限类

权限:可以限制用户访问的接口,比如说一个网站有两种用户,管理员和普通用户,那么管理员用户肯定拥有一些普通用户没有的权限。

1、权限类编写

# 继承BasePermission,重写has_permission,如果有权限,就返回True,没有权限就返回False
from rest_framework.permissions import BasePermission


class PermissionUser(BasePermission):
    def has_permission(self, request, view):
        # 如果有权限,返回True
        if request.user.user_type == 1:
            return True  # 超级用户允许访问
        else:
            return False

2、局部和全局使用

# 认证类的局部配置
from app01.auth import LoginAuth
class PubView(ModelViewSet):
     # 权限类:publish的5个接口,必须超级用户才能访问
    permission_classes = [PermissionUser]
    

# 全局使用
REST_FRAMEWORK={
    "DEFAULT_PERMISSION_CLASSES":["app01.auth.PermissionUser",]
}

三、drf之频率类

1、频率限制

限制用户的访问次数:根据用户ip地址限制

# 访问者IP地址
request.META.get('REMOTE_ADDR')
    
# 频率类的使用
'''
1、写一个类,继承SimpleRateThrottle,重写get_cache_key,返回ip就以ip限制
2、在类中写一个类属性:scope = 'ip_m_3'
'''

from rest_framework.throttling import BaseThrottle, SimpleRateThrottle


class MyThrotting(SimpleRateThrottle):
    # 类属性scope,名字随便取,在配置文件中配置雅阁与之对应的值
    scope = 'ip_m_3'

    def get_cache_key(self, request, view):
        # return了什么就以什么作为限制
        return request.META.get('REMOTE_ADDR')  # return的是一个ip地址

# 3 在settings.py中写
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_RATES': {
        # key值是频率类中scop字段对应的值,value是访问次数限制
        'ip_m_3': '3/m',
    }
}

2、局部和全局使用

# 1、局部使用-配置在视图类中
class IndexView(APIView):
    throttle_classes = [MyThrotting, ]  # 使用

    def get(self, request):
        return Response('ok')
       
# 2、全局使用-配置在settings.py中
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': ['app01.auth.MyThrotting',],
}

'''
如果要禁用某个视图类的频率类,就和局部使用差不多,只需要括号内导入的频率类删掉,成为一个空列表就可以了
throttle_classes = []
'''

额外小知识:可以拿到访问者的ip地址

class MyThrotting(SimpleRateThrottle):    scope = 'ip_m_3'    def get_cache_key(self, request, view):        return self.get_ident(request)  #返回访问者的ip:BaseThrottle的访问
posted @ 2021-09-13 15:12  黑影Poco  阅读(67)  评论(0)    收藏  举报