rest framework-认证,权限,节流

认证

1、主路由表

from django.contrib import admin
from django.urls import path, include

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

2、APP的mode

from django.db import models


class UserInfo(models.Model):
    user_type = (
        (1,'普通用户'),
        (2,'vip'),
        (3,'svip'),
    )
    user_type = models.IntegerField(choices=user_type)
    u_name = models.CharField(max_length=16,unique=True)
    u_password = models.CharField(max_length=64)

    class Meta:
        db_table = 'student'

    def to_dict(self):
        return {'id':self.id,'u_name':self.u_name,'u_password':self.u_password,'user_type':self.user_type}

class UserToken(models.Model):   #token表
    user = models.OneToOneField(to='UserInfo',on_delete=models.CASCADE)
    token = models.CharField(max_length=64)

3、APP路由表

from django.urls import path
from certification import views

urlpatterns = [
    path('request/', views.CBVget.as_view(), name='request'),
    path('lg/',views.CBVlogin.as_view(),name='lg')
]

4、APP的权限认证表

from rest_framework import exceptions
from rest_framework.views import APIView

from certification.models import UserInfo,UserToken
from rest_framework.authentication import BaseAuthentication

class Authtication(BaseAuthentication):

    def authenticate(self,request):    #做认证逻辑
        token = request.query_params.get('token')
        token_obj = UserToken.objects.filter(token=token).first()
        if not token_obj:
            data = {
                'code':10001,
                'msg':'认证失败'
            }
            raise exceptions.AuthenticationFailed(data)
        return (token_obj.user,token_obj)

    def authenticate_header(self,request):   #认证失败给浏览器返回的响应头
        pass

5、APP的views

from django.http import JsonResponse
from rest_framework.views import APIView   #rest_framework需要到setting里面设置
from certification.models import UserInfo,UserToken
import uuid
from certification.utils.auth import Authtication


class CBVget(APIView):

    authentication_classes = [Authtication,]  #也可以使用全局设置,在setting里面配置REST_FRAMEWORK={}
    def get(self,request,*args,**kwargs):  #根据权限查询人员信息信息
        user_list =UserInfo.objects.all()  #all获取的是all返回的是QuerySet对象,程序并没有真的在数据库中执行SQL语句查询数据
                                            # ,但支持迭代,使用for循环可以获取数据。
        user_list_json = []
        for user in user_list:
            user_list_json.append(user.to_dict())
        data ={
            'code':1000,
            'msg':'success',
            'data':user_list_json
        }
        return JsonResponse(data=data)


class CBVlogin(APIView):

    def post(self,request,*args,**kwargs):  #登录学生信息
           ret = {'code':1000,'msg':None}
           try:
               user = request._request.POST.get('u_name')
               pwd = request._request.POST.get('u_password')
               obj = UserInfo.objects.filter(u_name=user,u_password=pwd).first()  #查找匹配用户
               if not obj:
                   ret['code'] = 1001
                   ret['msg'] = '用户名或密码错误'
               #为用户创建token
               # token = uuid(user)
               token = uuid.uuid4().hex
               #存在就更新,不存在就创建
               UserToken.objects.update_or_create(user=obj,defaults={'token':token})
               ret['token'] = token
           except Exception as e:
               ret['code'] = '1002'
               ret['msg'] = '请求异常'
           return JsonResponse(ret)


认证知识点梳理:
    1、使用
        创建类:继承BaseAuthentication,实现authenticate方法
        返回值:
            none:不管,下一个认证来执行
            raise exceptions.AuthenticationFailed('用户认证失败')
            (元素1,元素2);元素1赋值给request.user,元素2赋值给request.auth
        局部使用:from rest_framework.authentication import BaseAuthentication,BasicAuthentication
            class UserInfo(APIView):
                authentication_classes = [BasicAuthentication]
                def get(self,request,*args,**kwargs):
                    print(request.user)
                    return HttpResponse('用户信息')
                    
        全部使用:
            REST_FRAMEWORK = {
            'DEFAULT_AUTHENTICATION_CLASSES':['cretification.utils.auth.Authtication'],
            'UNAUTHENTICATED_USER':None,   #匿名,request.user = None
            'UNAUTHENTICATED_TOKEN':None,  #匿名 request.auth = None
        }
        
    2、源码流程
        dispatch
            封装request
                获取定义的认证类(全局/局部),通过列表生成式创建对象
            initial
                perform authenticate
                    request.user (内部循环。。。)

权限

路由配置同上
1、权限表

from rest_framework.permissions import BasePermission


class MyPermission(BasePermission):
    message = '只有svip才可以访问'   #自定义返回的提示语
    def has_permission(self,request,view):
        if request.user.user_type != 3:
            return False
        return True

2、APP的view表

from django.http import JsonResponse
from rest_framework.views import APIView   #rest_framework需要到setting里面设置
from certification.utils.auth import Authtication
from certification.utils.permission import MyPermission

class CBVget(APIView):

    permission_classes = [MyPermission,]   #引用认证
    authentication_classes = [Authtication,]  #也可以使用全局设置,在setting里面配置REST_FRAMEWORK={}

    def get(self,request,*args,**kwargs):
        self.dispatch
        ret = {'code':2000,'msg':None,'data':None}
        try:
            return JsonResponse(data=ret)
        except Exception as e:
            pass
        return JsonResponse('查询失败')

使用SVIP用户访问的结果入下:
在这里插入图片描述
使用非SVIP用户访问的结果如下:
在这里插入图片描述
使用BasePermission实现的权限认证,与注册用户时自动根据用户名配置其权限信息

from django.http import JsonResponse
from rest_framework.views import APIView   #rest_framework需要到setting里面设置
from certification.models import UserInfo,UserToken
import uuid
from certification.utils.auth import Authtication
from certification.utils.permission import MyPermission

class CBVget(APIView):

    permission_classes = [MyPermission,]   #引用认证
    authentication_classes = [Authtication,]  #也可以使用全局设置,在setting里面配置REST_FRAMEWORK={}

    def get(self,request,*args,**kwargs):  #根据权限查询人员信息信息
        user_list =UserInfo.objects.all()  #all获取的是all返回的是QuerySet对象,程序并没有真的在数据库中执行SQL语句查询数据
        #                                     # ,但支持迭代,使用for循环可以获取数据。
        user_list_json = []
        user_token = request.query_params.get('token')  #获取用户的token信息
        user_id = UserToken.objects.get(token=user_token).user_id  #根据token获取user_id
        user_type = UserInfo.objects.get(id=user_id).user_type   #根据user_id获取用户类型
        if user_type == 3:
            for user in user_list:
                user_list_json.append(user.to_dict())
            data ={
                'code':2000,
                'msg':'success',
                'data':user_list_json
            }
            return JsonResponse(data=data)
        else:
            user_token = request.query_params.get('token')
            user_id = UserToken.objects.get(token=user_token).user_id
            user_list = UserInfo.objects.get(id=user_id)
            data ={
                'code':2000,
                'msg':'success',
                'data':user_list.to_dict()
            }
            return JsonResponse(data=data)


class CBVlogin(APIView):

    def post(self,request,*args,**kwargs):  #登录学生信息
        # action = request._request.GET.get('action')  #query_params等于_request.GET,进到源码查看
        action = request.query_params.get('action')
        if action == 'login':
            ret = {'code':1000,'msg':None}
            try:
                user = request._request.POST.get('u_name')
                pwd = request._request.POST.get('u_password')
                obj = UserInfo.objects.filter(u_name=user,u_password=pwd).first()  #查找匹配用户
                if not obj:
                    ret['code'] = 1001
                    ret['msg'] = '用户名或密码错误'
                #为用户创建token
                # token = uuid(user)
                token = uuid.uuid4().hex
                #存在就更新,不存在就创建
                UserToken.objects.update_or_create(user=obj,defaults={'token':token})
                ret['token'] = token
            except Exception as e:
                ret['code'] = '1002'
                ret['msg'] = '请求异常'
            return JsonResponse(ret)

        elif action == 'regist':    #注册用户,根据用户名直接设置该用户的角色
            user_type_svip = ['cq','yyx']   #用户配置表可以放到一块,再引用过来
            user_type_vip = ['zjj','lfr']
            user = request._request.POST.get('u_name')
            pwd = request._request.POST.get('u_password')
            users = UserInfo()
            users.u_name = user
            users.u_password = pwd
            print(user,pwd)
            if user in user_type_svip:
                user_type = 3
                users.user_type = user_type
            elif user in user_type_vip:
                user_type = 2
                users.user_type = user_type
            else:
                user_type = 1
                users.user_type = user_type
            users.save()
            ret = {
                'code': 2000,
                'msg': '新增用户成功',
            }
            return JsonResponse(ret)


权限知识点梳理:
    1、使用
        类:必须继承:BasePermission 必须实现:has_permission方法
        
        返回值:
            -True:有权访问
            -False:无权访问
            
        局部使用:
            permission_classes = [MyPermission,] 
            def get(self,request,*args,**kwargs):
                return HttpResponse('用户信息')
                
        全局配置:
        
          REST_FRAMEWORK = {
            'DEFAULT_PERMISSION_CLASSES':['cretification.utils.permission.MyPermission']
        }
           
    

节流

路由配置同上
1、APP节流表

import time
from rest_framework.throttling import BaseThrottle,SimpleRateThrottle


VISIT_RECORD = {}   #设置的全局,重启就没了,可以放到数据库或者缓存


class VisitThrottle(BaseThrottle):
    """60秒内访问3次"""

    def __init__(self):
        self.history = None

    def allow_request(self, request, view):
        # 获取用户ip
        # ip_addr = self.get_ident(request)  #类自带的获取ip的方法
        ip_addr = request.META.get('REMOTE_ADDR')
        ctime = time.time()
        if ip_addr not in VISIT_RECORD:
            VISIT_RECORD[ip_addr] = [ctime]
            return True
        history = VISIT_RECORD.get(ip_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  #表示可以访问,反之不可以访问

    def wait(self):
        """显示还有多少秒可以访问"""
        ctime = time.time()
        return 60 - (ctime - self.history[-1])  # 得到可以访问的时间


#类自带的实现次数限定,
class VisitThrottle(SimpleRateThrottle):
    """
    设置,根据IP限制每分钟访问3次
    """
    scope = 'cc'  #随意写,源码当做key值调用  需要到配置文件设置
    def get_cache_key(self, request, view):
        # self.parse_rate()   #可以到源码查看,配置文件设置时间和次数的格式
        return self.get_ident(request)


2、APP的view

from django.http import JsonResponse
from rest_framework.views import APIView   #rest_framework需要到setting里面设置
from certification.models import UserInfo,UserToken
import uuid
from certification.utils.auth import Authtication
from certification.utils.permission import MyPermission
from certification.utils.throttle import VisitThrottle

class CBVget(APIView):

    permission_classes = [MyPermission,]   #引用认证
    authentication_classes = [Authtication,]  #也可以使用全局设置,在setting里面配置REST_FRAMEWORK={}
    throttle_classes = [VisitThrottle,]   #节流


    def get(self,request,*args,**kwargs):  #根据权限查询人员信息信息
        user_list =UserInfo.objects.all()  #all获取的是all返回的是QuerySet对象,程序并没有真的在数据库中执行SQL语句查询数据
        #                                     # ,但支持迭代,使用for循环可以获取数据。
        user_list_json = []
        user_token = request.query_params.get('token')  #获取用户的token信息
        user_id = UserToken.objects.get(token=user_token).user_id  #根据token获取user_id
        user_type = UserInfo.objects.get(id=user_id).user_type   #根据user_id获取用户类型
        if user_type == 3:
            for user in user_list:
                user_list_json.append(user.to_dict())
            data ={
                'code':2000,
                'msg':'success',
                'data':user_list_json
            }
            return JsonResponse(data=data)
        else:
            user_token = request.query_params.get('token')
            user_id = UserToken.objects.get(token=user_token).user_id
            user_list = UserInfo.objects.get(id=user_id)
            data ={
                'code':2000,
                'msg':'success',
                'data':user_list.to_dict()
            }
            return JsonResponse(data=data)

class CBVlogin(APIView):

    def post(self,request,*args,**kwargs):  #登录学生信息
        # action = request._request.GET.get('action')  #query_params等于_request.GET,进到源码查看
        action = request.query_params.get('action')
        if action == 'login':
            ret = {'code':1000,'msg':None}
            try:
                user = request._request.POST.get('u_name')
                pwd = request._request.POST.get('u_password')
                obj = UserInfo.objects.filter(u_name=user,u_password=pwd).first()  #查找匹配用户
                if not obj:
                    ret['code'] = 1001
                    ret['msg'] = '用户名或密码错误'
                #为用户创建token
                # token = uuid(user)
                token = uuid.uuid4().hex
                #存在就更新,不存在就创建
                UserToken.objects.update_or_create(user=obj,defaults={'token':token})
                ret['token'] = token
            except Exception as e:
                ret['code'] = '1002'
                ret['msg'] = '请求异常'
            return JsonResponse(ret)

        elif action == 'regist':    #注册用户,根据用户名直接设置该用户的角色
            user_type_svip = ['cq','yyx']   #用户配置表可以放到一块,再引用过来
            user_type_vip = ['zjj','lfr']
            user = request._request.POST.get('u_name')
            pwd = request._request.POST.get('u_password')
            users = UserInfo()
            users.u_name = user
            users.u_password = pwd
            print(user,pwd)
            if user in user_type_svip:
                user_type = 3
                users.user_type = user_type
            elif user in user_type_vip:
                user_type = 2
                users.user_type = user_type
            else:
                user_type = 1
                users.user_type = user_type
            users.save()
            ret = {
                'code': 2000,
                'msg': '新增用户成功',
            }
            return JsonResponse(ret)


超时的效果图
在这里插入图片描述

知识点梳理:
    1、基本使用
    类:继承BaseThrottle ,实现:allow_request  wait
    类: 继承SimpleRateThrottle   实现:get_cache_key   scope = 'cc' ==>配置文件中的key
    
    2、局部
         throttle_classes = [VisitThrottle,]   #节流
         
    3、全局
    REST_FRAMEWORK = {
    'DEFAULT_THROTTL_RATES':{
      'cc':"3/m"                        #代码每一分钟访问3次,具体可以进到源码parse_rate查看设置方式
    },
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值