restful知识点之三restframework认证-->权限-->频率

 

认证、权限、频率是层层递进的关系

  权限业务时:认证+权限

  频率业务时:认证+权限+频率

局部认证方式

 

from django.conf.urls import url,include
from django.contrib import admin
from api import views

urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    url(r'^auth/', views.AuthView.as_view()),
    url(r'^books/', views.booksView.as_view()),
    url(r'^books_detail/(\d+)/$', views.book_detail.as_view()),
    url(r'^oderDetial/$', views.OderDetialView.as_view()),

]
urls.py

 

from rest_framework.views import APIView
from api.models import *
import uuid
from django.http import JsonResponse
from rest_framework.response import Response#渲染器
from api.util.Myserializer import BookSerializers
from rest_framework import exceptions#抛异常
from rest_framework.generics import GenericAPIView
from rest_framework.viewsets import GenericViewSet
from rest_framework.authentication import BaseAuthentication

# Create your views here.


ORDER_DICT = {
    1:{
        'name': "媳妇",
        'age':18,
        'gender':'',
        'content':'...'
    },
    2:{
        'name': "老狗",
        'age':19,
        'gender':'',
        'content':'...。。'
    },
}

class AuthView(APIView):
    def post(self,request):

        ret={'code':1000,'msg':None}
        # 从前端获取用户名密码
        try:
            user=request._request.POST.get('username')
            pwd=request._request.POST.get('password')
        #     取数据库校验
            obj=User.objects.filter(name=user,pwd=pwd).first()

            if not obj:
                ret['code']=1001
                ret['msg']='用户名密码错误'
        #     登录成功生成token写入token表(如果有则更新,没有则创建)
            token=str(uuid.uuid4())
            Token.objects.update_or_create(user=obj,defaults={'token':token})
            ret['token']=token
        except Exception as e:
            ret['code']=1002
            ret['msg']='请求异常'
        return JsonResponse(ret)

class Authtication(object):
    def authenticate(self,request):
        # 接收来自前端发来的token值
        token = request._request.GET.get('token')
#         从数据库中查找
        token_obj=Token.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationFailed('用户认证失败')
        # 在rest_framework内部会将两个字段赋值给request,以供后续使用
        return (token_obj.user,token_obj)
    def authenticate_header(self,request):
        pass





class OderDetialView(APIView):
   authentication_classes = [Authtication,]
   def get(self,request):
       ret={'code':1000,'msg':None,'data':None}

       ret['data']=ORDER_DICT
       return JsonResponse(ret)
views.py

 

from django.db import models

# Create your models here.
from django.db import models

# Create your models here.

class User(models.Model):
    name=models.CharField(max_length=32)
    pwd=models.CharField(max_length=32)
    type_choices=((1,"普通用户"),(2,"VIP"),(3,"SVIP"))
    user_type=models.IntegerField(choices=type_choices,default=1)


class Token(models.Model):
    user=models.OneToOneField("User")
    token = models.CharField(max_length=128)

    def __str__(self):
        return self.token
modesl.py

 

 

 

 

 

postman执行:

  

 

全局认证方式

settings.py配置如下:

REST_FRAMEWORK={
'DEFAULT_AUTHENTICATION_CLASSES':['app02.service.auth.Authtication',
]
}
from app02.models import *
from rest_framework import exceptions

#不继承BaseAuthentication也可以
class Authtication(object):
    def authenticate(self,request):
        token=request._request.GET.get('token')
        token_obj=UserToken.objects.filter(token=token).first()
        if not token_obj:
            raise  exceptions.AuthenticationFailed('用户认证失败')
       #rest framework内部会将这两个字段赋值给request,以供后续操作使用
        return (token_obj.user,token_obj)

    def authenticate_header(self, request):
            pass
app02.service.auth.py

 

 认证源码分析流程:

 权限

class permission(object):
    def has_permission(self,request,view):
        if request.user.user_type !=2:
            return True
        return False
    
    
class OderDetialView(APIView):
   # authentication_classes = [Authtication,]
   permission_classes = [permission,]
   def get(self,request):
       ret={'code':1000,'msg':None,'data':None}
       print(request.user.user_type,
    'user表中填入的user_type类型,
    权限认证时重新封装了新的request.user(user是数据库关联字段)
) if request.user.user_type==2: ret['data']=ORDER_DICT return JsonResponse(ret)

 频率

import time
VISIT_RECORD = {}   # 格式是{id:[time2]}

# 访问频率类
class VisitThrottle(object):
    """60秒内只能访问3次"""
    def __init__(self):
        self.history = None

    def allow_request(self, request, view):
        # 获取用户IP
        remote_addr = request.META.get('REMOTE_ADDR')
        ctime = time.time()
        print(remote_addr)
        if remote_addr not in VISIT_RECORD:  # 如果是第一次访问,就存放访问时间以及IP地址
            VISIT_RECORD[remote_addr] = [ctime,]   # 添加到VISIT_RECORD中
            return True
        history = VISIT_RECORD.get(remote_addr)  # 不是第一次访问,先获取记录
        self.history = history
        print("111:",history)
        while history and history[-1] < ctime - 60:   # 如果最早一次访问时间超过一分钟,就删掉 去掉history and  后把while改成if,可以实现一样的功能
# 上一行代码中while循环一直循环,如果列表history为空,循环的时候都会报错,因为找不到history[-1]这个值,所以要加上history,用来跳出循环,防止代码出错
            history.pop()

        if len(history) < 3:  # 不用写else,如果不小于3,会有错误处理机制,直接拒绝访问。
            history.insert(0, ctime)  # 按照索引插入元素
            return True
    def wait(self):
        ctime = time.time()
        return 60 - (ctime - self.history[-1])

 

posted @ 2018-05-20 11:58  强仔必胜  阅读(383)  评论(0编辑  收藏  举报