Django REST framework之版本、认证、权限、访问控制

安装与配置

安装:
pip install djangorestframework
pip install markdown     # 可选依赖包
pip install django-filter  # 可选依赖包
配置
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'ApiView',
'rest_framework', # 注册
]

REST_FRAMEWORK = {
  'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning', # /api/v1/users/ 版本配置
  'DEFAULT_VERSION':'v1', # 默认版本
  'ALLOWED_VERSIONS':['v1','v2'], # 可用版本
  'VERSION_PARAM':'version', # 版本参数
    'DEFAULT_AUTHENTICATION_CLASSES':['ApiView.auth.AuthClass.Auth',], # 全局验证
'UNAUTHENTICATED_USER':None, # 匿名,request.user
'UNAUTHENTICATED_TOKEN':None, # 匿名,request.auth
'DEFAULT_PERMISSION_CLASSES':['ApiView.permission.PermissionClass.VipPermission',], # 全局权限
'DEFAULT_THROTTLE_CLASSES':['ApiView.throttle.ThrottleClass.UserThrottle',], # 全局频率限制
'DEFAULT_THROTTLE_RATES':{
'anonymous':'3/m', # 匿名用户3次/分钟
'user':'10/m', # 登陆用户10次/分钟
},
    'UNICODE_JSON': False, # 编码格式
}

基本使用 

目录格式:

一、models.py:数据库创建

from django.db import models

# Create your models here.

class UserInfo(models.Model):
    user_type_choices = (
        ('普通用户',1),
        ('会员用户',2),
        ('管理员',3),
    )
    user_type = models.CharField(choices=user_type_choices,max_length=32)
    username = models.CharField(max_length=32,unique=True)
    password = models.CharField(max_length=64)

    def __str__(self):
        return self.username

class AuthToken(models.Model):
    user = models.OneToOneField(to=UserInfo,on_delete=models.CASCADE)
    token = models.CharField(max_length=255)

二、views.py:视图文件内容

from django.http import JsonResponse
from rest_framework.views import APIView 
from ApiView import models
from ApiView.util.tools import Utools


class AuthView(APIView):
    """
    用于用户登陆
    """
    
    authentication_classes = []
    permission_classes = []
    from ApiView.throttle.ThrottleClass import AuthThrottle
    throttle_classes = [AuthThrottle, ]
    def post(self, request,*args,**kwargs):
        '''
        登陆
        :param request:
        :return:
        '''
        ret = {'code': 1000, 'msg': None}
        try:
            user = request._request.POST.get('username')
            pwd = request._request.POST.get('password')
            obj = models.UserInfo.objects.filter(username=user,password=pwd).first()
            if not obj:
                ret['code'] = 1001
                ret['msg'] = "用户名或密码错误"

            # 为用户创建token
            token = Utools.md5(user)
            models.AuthToken.objects.update_or_create(user=obj,defaults={'token':token})
            ret['msg'] = '认证成功'
            ret['token'] = token
        except Exception as e:
            ret['code'] = 1002
            ret['msg'] = "登陆请求异常"

        return JsonResponse(ret)


# 模拟订单数据
order_dict = {
    1:{
        'name':'苹果',
        'price':5,
        'content':'这是一个苹果'
    },
    2:{
        'name':'香蕉',
        'price':7,
        'content':'这是一个香蕉'
    },
}
class OrderView(APIView):
    """
    订单相关业务
    """
    def get(self, request,*args,**kwargs):
        ret = {'code': 1000, 'msg': None,'data':None}
        try:
            ret['data'] = order_dict
        except Exception as e:
            pass

        return JsonResponse(ret)

三、版本:version.py

from django.shortcuts import render,HttpResponse
from django.urls import reverse
from rest_framework.views import APIView
from rest_framework.request import Request
# Create your views here.
# 自定义
# class ParamVersion(BaseVersioning):
#     def determine_version(self, request, *args, **kwargs):
#         version = request.query_params.get('version')
#         return version


class UsersView(APIView):

    def get(self,request,*args,**kwargs):

        print(request.version) # 获取版本
        print(request.versioning_scheme) # 获取处理版本的对象

        # rest_framework 反向生成url
        print(request.versioning_scheme.reverse(viewname='usersss',request=request))
        # django 自带反向生成url
        print(reverse(viewname='userspath',kwargs={'version':request.version}))
        return HttpResponse('用户列表')

四、登陆认证:AuthClass.py

from rest_framework.exceptions import AuthenticationFailed
from rest_framework.authentication import BaseAuthentication
from ApiView import models

class Auth(BaseAuthentication):
    """
    认证控制
    """
    def authenticate(self, request):
        token = request._request.GET.get('token')
        token_obj = models.AuthToken.objects.filter(token=token).first()
        if not token_obj:
            raise AuthenticationFailed({'code': 1001, 'error': '认证失败'})

        # 在内部将这两个字段赋值给request.user和request.auth
        return (token_obj.user,token_obj)

    def authenticate_header(self,request):
        pass

class AnonymousAuth(BaseAuthentication):
    def authenticate(self, request):
        pass

    def authenticate_header(self,request):
        pass

五、权限认证:PermissionClass.py

from rest_framework.permissions import BasePermission
from ApiView import models


class VipPermission(BasePermission):
    """
    权限控制
    """
    message = '无权限访问'

    def has_permission(self, request, view):
        try:
            if request.user.user_type == '1':
                return False
        except Exception as e:
            return False

        return True

六、访问控制(频率):ThrottleClass.py

from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
import time

"""
# 自定义
# 登陆访问控制/匿名用户
Access_record = {}
class AuthThrottle(BaseThrottle):
    # 访问控制
    def __init__(self):
        self.record = None
        self.settime = 60

    # 判断频率是否达到最大限度  例子:同一IP,60秒内只能访问3次
    def allow_request(self, request, view):
        # 获取用户ip
        remote_addr = self.get_ident(request)
        ctime = time.time()
        if remote_addr not in Access_record:
            Access_record[remote_addr] = [ctime, ]
            return True  # 表示可以访问

        self.record = Access_record.get(remote_addr)
        # self.record = record
        # 如果有记录,并且最后一个记录时间小于60秒以前
        while self.record and self.record[-1] < ctime-self.settime:
            # 则删掉存储的时间记录
            self.record.pop(-1)

        # 如果记录时间小于3次则添加当前时间到记录中
        if len(self.record) < 3:
            self.record.insert(0,ctime)
            return True


    def wait(self):
        # 还需要等多久
        ctime = time.time()
        return self.settime - (ctime - self.record[-1])
"""

#  使用框架自带/匿名用户
class AuthThrottle(SimpleRateThrottle):
    scope = 'anonymous'
    def get_cache_key(self, request, view):
        return self.get_ident(request)


# 其他接口访问控制
class UserThrottle(SimpleRateThrottle):
    scope = 'user'
    def get_cache_key(self, request, view):
        return request.user.username

 六、权限认证时使用生成token的md5方法

import hashlib,time


class Utools(object):
    """
    公共方法
    """

    # md5生成
    @classmethod
    def md5(cls,user):
        ctime = str(time.time())
        m = hashlib.md5(bytes(user, encoding='utf-8'))
        m.update(bytes(ctime, encoding='utf-8'))
        return m.hexdigest()

if __name__ == '__main__':
    f = Utools.md5(user='bb')
    print(f)
 注:顺序为 版本 --  认证 -- 授权 -- 访问次数/频率
posted @ 2019-04-14 17:50  我在地球凑人数的日子  阅读(213)  评论(0)    收藏  举报