Django REST framework 认证、权限和频率组件

认证与权限频率组件

身份验证是将传入请求与一组标识凭据(例如请求来自的用户或其签名的令牌)相关联的机制。然后 权限 和 限制 组件决定是否拒绝这个请求。

简单来说就是:

  • 认证确定了你是谁
  • 权限确定你能不能访问某个接口
  • 限制确定你访问某个接口的频率

一、认证组件

REST framework 提供了一些开箱即用的身份验证方案,并且还允许你实现自定义方案。

自定义Token认证

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

class UserInfo(models.Model):username = models.CharField(max_length=16)password = models.CharField(max_length=32)type = models.SmallIntegerField(choices=((1, '普通用户'), (2, 'VIP用户')),default=1)class Token(models.Model):user = models.OneToOneField(to='UserInfo')token_code = models.CharField(max_length=128)

定义一个登录视图:

def get_random_token(username):"""根据用户名和时间戳生成随机token:param username::return:"""import hashlib, timetimestamp = str(time.time())m = hashlib.md5(bytes(username, encoding="utf8"))m.update(bytes(timestamp, encoding="utf8"))return m.hexdigest()class LoginView(APIView):"""校验用户名密码是否正确从而生成token的视图"""def post(self, request):res = {"code": 0}print(request.data)username = request.data.get("username")password = request.data.get("password")user = models.UserInfo.objects.filter(username=username, password=password).first()if user:# 如果用户名密码正确token = get_random_token(username)models.Token.objects.update_or_create(defaults={"token_code": token}, user=user)res["token"] = tokenelse:res["code"] = 1res["error"] = "用户名或密码错误"return Response(res)

定义一个认证类

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailedclass MyAuth(BaseAuthentication):def authenticate(self, request):     # 必须实现authenticate方法,返回(认证之后的用户,认证的obj)if request.method in ["POST", "PUT", "DELETE"]:request_token = request.data.get("token", None)if not request_token:raise AuthenticationFailed('缺少token')token_obj = models.Token.objects.filter(token_code=request_token).first()if not token_obj:raise AuthenticationFailed('无效的token')return token_obj.user.username, Noneelse:return None, None

视图级别认证

class CommentViewSet(ModelViewSet):queryset = models.Comment.objects.all()serializer_class = app01_serializers.CommentSerializerauthentication_classes = [MyAuth, ]

全局级别认证

# 在settings.py中配置
REST_FRAMEWORK = {"DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ]
}

二、权限组件

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

自定义一个权限类

# 自定义权限
class MyPermission(BasePermission):message = 'VIP用户才能访问'def has_permission(self, request, view):"""必须实现has_permission,有权限返回True,无权限返回False"""# 因为在进行权限判断之前已经做了认证判断,所以这里可以直接拿到request.userif request.user and request.user.type == 2:  # 如果是VIP用户return Trueelse:return False

视图级别配置

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

全局级别设置

# 在settings.py中设置rest framework相关配置项
REST_FRAMEWORK = {"DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ],"DEFAULT_PERMISSION_CLASSES": ["app01.utils.MyPermission", ]
}

三、频率限制组件

DRF内置了基本的限制类,首先我们自己动手写一个限制类,熟悉下限制组件的执行过程。

自定义限制类

VISIT_RECORD = {}
# 自定义限制
class MyThrottle(object):def __init__(self):self.history = Nonedef allow_request(self, request, view): """必须实现allow_request,允许访问返回True,否则返回False自定义频率限制60秒内只能访问三次"""# 获取用户IPip = request.META.get("REMOTE_ADDR")timestamp = time.time()if ip not in VISIT_RECORD:VISIT_RECORD[ip] = [timestamp, ]return Truehistory = VISIT_RECORD[ip]self.history = historyhistory.insert(0, timestamp)while history and history[-1] < timestamp - 60:history.pop()if len(history) > 3:return Falseelse:return Truedef wait(self):"""限制时间还剩多少"""timestamp = time.time()return 60 - (timestamp - self.history[-1])

视图使用

class CommentViewSet(ModelViewSet):queryset = models.Comment.objects.all()serializer_class = app01_serializers.CommentSerializerthrottle_classes = [MyThrottle, ]

全局使用

# 在settings.py中设置rest framework相关配置项
REST_FRAMEWORK = {"DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ],"DEFAULT_PERMISSION_CLASSES": ["app01.utils.MyPermission", ],"DEFAULT_THROTTLE_CLASSES": ["app01.utils.MyThrottle", ]
}

使用内置限制类

from rest_framework.throttling import SimpleRateThrottleclass VisitThrottle(SimpleRateThrottle):scope = "xxx"def get_cache_key(self, request, view):return self.get_ident(request)

全局配置

# 在settings.py中设置rest framework相关配置项
REST_FRAMEWORK = {"DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ],# "DEFAULT_PERMISSION_CLASSES": ["app01.utils.MyPermission", ]"DEFAULT_THROTTLE_CLASSES": ["app01.utils.VisitThrottle", ],"DEFAULT_THROTTLE_RATES": {"xxx": "5/m",}
}

认证类源码

############################ authentication.py ####################################
from __future__ import unicode_literalsimport base64
import binasciifrom django.contrib.auth import authenticate, get_user_model
from django.middleware.csrf import CsrfViewMiddleware
from django.utils.six import text_type
from django.utils.translation import ugettext_lazy as _from rest_framework import HTTP_HEADER_ENCODING, exceptionsdef get_authorization_header(request):"""Return request's 'Authorization:' header, as a bytestring.Hide some test client ickyness where the header can be unicode."""auth = request.META.get('HTTP_AUTHORIZATION', b'')if isinstance(auth, text_type):# Work around django test client oddnessauth = auth.encode(HTTP_HEADER_ENCODING)return authclass CSRFCheck(CsrfViewMiddleware):def _reject(self, request, reason):# Return the failure reason instead of an HttpResponsereturn reasonclass BaseAuthentication(object):"""All authentication classes should extend BaseAuthentication."""def authenticate(self, request):"""Authenticate the request and return a two-tuple of (user, token)."""raise NotImplementedError(".authenticate() must be overridden.")def authenticate_header(self, request):"""Return a string to be used as the value of the `WWW-Authenticate`header in a `401 Unauthenticated` response, or `None` if theauthentication scheme should return `403 Permission Denied` responses."""passclass BasicAuthentication(BaseAuthentication):"""HTTP Basic authentication against username/password."""www_authenticate_realm = 'api'def authenticate(self, request):"""Returns a `User` if a correct username and password have been suppliedusing HTTP Basic authentication.  Otherwise returns `None`."""auth = get_authorization_header(request).split()if not auth or auth[0].lower() != b'basic':return Noneif len(auth) == 1:msg = _('Invalid basic header. No credentials provided.')raise exceptions.AuthenticationFailed(msg)elif len(auth) > 2:msg = _('Invalid basic header. Credentials string should not contain spaces.')raise exceptions.AuthenticationFailed(msg)try:auth_parts = base64.b64decode(auth[1]).decode(HTTP_HEADER_ENCODING).partition(':')except (TypeError, UnicodeDecodeError, binascii.Error):msg = _('Invalid basic header. Credentials not correctly base64 encoded.')raise exceptions.AuthenticationFailed(msg)userid, password = auth_parts[0], auth_parts[2]return self.authenticate_credentials(userid, password, request)def authenticate_credentials(self, userid, password, request=None):"""Authenticate the userid and password against username and passwordwith optional request for context."""credentials = {get_user_model().USERNAME_FIELD: userid,'password': password}user = authenticate(request=request, **credentials)if user is None:raise exceptions.AuthenticationFailed(_('Invalid username/password.'))if not user.is_active:raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))return (user, None)def authenticate_header(self, request):return 'Basic realm="%s"' % self.www_authenticate_realmclass SessionAuthentication(BaseAuthentication):"""Use Django's session framework for authentication."""def authenticate(self, request):"""Returns a `User` if the request session currently has a logged in user.Otherwise returns `None`."""# Get the session-based user from the underlying HttpRequest objectuser = getattr(request._request, 'user', None)# Unauthenticated, CSRF validation not requiredif not user or not user.is_active:return Noneself.enforce_csrf(request)# CSRF passed with authenticated userreturn (user, None)def enforce_csrf(self, request):"""Enforce CSRF validation for session based authentication."""check = CSRFCheck()# populates request.META['CSRF_COOKIE'], which is used in process_view()check.process_request(request)reason = check.process_view(request, None, (), {})if reason:# CSRF failed, bail with explicit error messageraise exceptions.PermissionDenied('CSRF Failed: %s' % reason)class TokenAuthentication(BaseAuthentication):"""Simple token based authentication.Clients should authenticate by passing the token key in the "Authorization"HTTP header, prepended with the string "Token ".  For example:Authorization: Token 401f7ac837da42b97f613d789819ff93537bee6a"""keyword = 'Token'model = Nonedef get_model(self):if self.model is not None:return self.modelfrom rest_framework.authtoken.models import Tokenreturn Token"""A custom token model may be used, but must have the following properties.* key -- The string identifying the token* user -- The user to which the token belongs"""def authenticate(self, request):auth = get_authorization_header(request).split()if not auth or auth[0].lower() != self.keyword.lower().encode():return Noneif len(auth) == 1:msg = _('Invalid token header. No credentials provided.')raise exceptions.AuthenticationFailed(msg)elif len(auth) > 2:msg = _('Invalid token header. Token string should not contain spaces.')raise exceptions.AuthenticationFailed(msg)try:token = auth[1].decode()except UnicodeError:msg = _('Invalid token header. Token string should not contain invalid characters.')raise exceptions.AuthenticationFailed(msg)return self.authenticate_credentials(token)def authenticate_credentials(self, key):model = self.get_model()try:token = model.objects.select_related('user').get(key=key)except model.DoesNotExist:raise exceptions.AuthenticationFailed(_('Invalid token.'))if not token.user.is_active:raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))return (token.user, token)def authenticate_header(self, request):return self.keywordclass RemoteUserAuthentication(BaseAuthentication):"""REMOTE_USER authentication.To use this, set up your web server to perform authentication, which willset the REMOTE_USER environment variable. You will need to have'django.contrib.auth.backends.RemoteUserBackend in yourAUTHENTICATION_BACKENDS setting"""# Name of request header to grab username from.  This will be the key as# used in the request.META dictionary, i.e. the normalization of headers to# all uppercase and the addition of "HTTP_" prefix apply.header = "REMOTE_USER"def authenticate(self, request):user = authenticate(remote_user=request.META.get(self.header))if user and user.is_active:return (user, None)

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/454442.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高速率AVS整数变换的汇编实现与优化

1 引言 AVS标准Ⅲ采用的8x8整数变换在获得较H&#xff0e;264更高的压缩率和主观图像质量的同时&#xff0c;增加了算法的实现复杂性和时间开销。本文重点研究AVS编解码器的整数变换模块&#xff0c;针对不同的算法实现模式&#xff0c;在原有Visual C6&#xff0e;0整数变换模…

计算机与广播电视论文,浅谈广播电视中计算机技术的作用论文.pdf

1、计算机技术在广播电视的媒体内容中有重要应用在以往的广播电视中&#xff0c; 媒体内容主要分为音频和视频两种信号&#xff0c; 在传输的过程中使用的是模拟信号&#xff0c; 但模拟信号受到的外界干扰因素较为明显&#xff0c; 因此广播电视传播的媒体内容受到影响&#x…

opencv安装教程python3.7_Mac下安装使用Python-OpenCV,解决opencv3安装完成无法使用的问题 - pytorch中文网...

OpenCV是一个跨平台计算机视觉库&#xff0c;可以运行在Linux、Windows、Android和Mac OS操作系统上。提供了Python、Ruby、MATLAB等语言的接口&#xff0c;实现了图像处理和计算机视觉方面的很多通用算法。 Mac安装OpenCV 在我们的深度学习的过程中&#xff0c;对于图像&#…

NodeJS在CentOs7下安装

node下载地址:https://nodejs.org/en/download/ 1.安装gcc $ yum install gcc-c 2.解压最新版本 $ mkdir /usr/local/node$ tar zxvf node-v6.11.4.tar.gz $ cd node-v6.11.4$ ./configure --prefix/usr/local/node# 在当前目录下编译安装Node$ make$ make install 3.验证安装 …

Python功能之反射

有如下文件: index.py 1<span style"font-family:宋体, SimSun;">#!/usr/bin/env python<br data-filtered"filtered"># -*- coding:utf-8 -*-<br data-filtered"filtered">__author__ ryan<br data-filtered"filter…

Django REST framework 分页

分页模式 rest framework中提供了三种分页模式&#xff1a; from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination 全局配置 REST_FRAMEWORK {DEFAULT_PAGINATION_CLASS: rest_framework.pagination.LimitOffsetPaginat…

解析H.264视频编解码DSP实现与优化

引言 基于互联网的数字视频产业前景看好&#xff0c;而3G的规模部署&#xff0c;也会推动移动视频通信成为现实。但数字化后的视频图像具有数据海量性&#xff0c;给图像的存储和传输造成较大的困难。数字视频产业&#xff0c;是指数字内容中以数字视频形态为主的文化创意和传播…

ap计算机科学a买什么书,准备AP*计算机科学A考试-第1部分

你将学到什么Identify the use and proper use of Variables, Conditionals, Objects and primitives, control structures, booleans, lists and arrays, and Exceptions.Implement problem descriptions in well designed code.Identify and begin to design algorithms to s…

python 打包exe_python如何封装为exe

1、首先进入python安装路径D:\Python27\Scripts下&#xff0c;查看pip或easy_install是否安装。2、确保安装了pip或者easy_install&#xff0c;在cmd命令行下输入“easy_install”&#xff0c;没有提示“xxx不是内部或外部命令……”&#xff0c;就说明easy install工具安装成功…

CentOS7安装Hadoop2.7完整步骤

总体思路&#xff0c;准备主从服务器&#xff0c;配置主服务器可以无密码SSH登录从服务器&#xff0c;解压安装JDK&#xff0c;解压安装Hadoop&#xff0c;配置hdfs、mapreduce等主从关系。 1、环境&#xff0c;3台CentOS7&#xff0c;64位&#xff0c;Hadoop2.7需要64位Linux&…

Django REST framework 解析器和渲染器

解析器的作用 解析器的作用就是服务端接收客户端传过来的数据&#xff0c;把数据解析成自己可以处理的数据。本质就是对请求体中的数据进行解析。 在了解解析器之前&#xff0c;我们要先知道Accept以及ContentType请求头。 Accept是告诉对方我能解析什么样的数据&#xff0c…

MyBatis的学习之路(二)

上篇文章介绍了MyBatis的配置文件&#xff0c;现在来介绍实体映射文件Mapper.xml。 说道实体映射文件&#xff0c;就不得不说一下实体与表之间的映射关系&#xff1a;单表映射和多表映射。 a. 单表映射 1 public class Admin{ 2 private String id; 3 private String n…

计算机一级实验素材题目,计算机一级EXCEL操作题整理素材(12页)-原创力文档...

素材摘录&#xff0c;文档可编辑分享PAGE 页码页码/NUMPAGES 总页数总页数单元格合并首先选中你要合并的单元格&#xff0c;然后找到EXCEL上的开始分区里的这种图标或者是含有“合并”两字的位置如图1-1&#xff0c;如果题目要求的是要你合并单元格并让内容居中&#xff0c;你就…

python爬取toefl_spark学习进度6-Python爬取数据的四个简单实例

今天本来想把昨天安装的intellij配置好&#xff0c;但是一直显示没有网络&#xff0c;网上查了相关资料也没有查出来解决办法。然后暂停了intellij的配置&#xff0c;开始做了几个Python爬取简单数据的实例&#xff0c;先做了几个最简单的&#xff0c;以后再加大难度&#xff0…

Django REST framework 版本

API 版本控制允许我们在不同的客户端之间更改行为&#xff08;同一个接口的不同版本会返回不同的数据&#xff09;。 DRF提供了许多不同的版本控制方案。 可能会有一些客户端因为某些原因不再维护了&#xff0c;但是我们后端的接口还要不断的更新迭代&#xff0c;这个时候通过…

AngularJS中的过滤器(filter)

AngularJS中的过滤器是用于对数据的格式化&#xff0c;或者筛选的函数&#xff0c;可以直接通过以下语法使用&#xff1a; {{expression|filter}} {{expression|filter1|filter2}} {{expression|filter1:param1,param2,...|filter2} 过滤器的种类有number&#xff0c;currency&…

计算机考试上传照片教程,电脑照片传到iPhone手机的详细步骤【图文】

苹果自带的iOS系统是不可以随便和电脑进行数据交换的&#xff0c;必须使用iTunes软件。许多用户为此问题困扰&#xff0c;我们有什么可以把电脑照片传到iPhone手机&#xff1f;下面我们就一起来看看把电脑照片传到iphone设备的详细步骤。具体方法如下&#xff1a;1&#xff0c;…

javaweb 导出文件名乱码的问题解决方案

fileName new String(fileName.getBytes("ISO8859-1"), "UTF-8"); 或者 String finalFileName null; if(StringUtils.contains(userAgent, "MSIE")){//IE浏览器 finalFileName URLEncoder.encode(fileName,"UTF8"); }else if(Str…

AVS 分像素运动估计优化算法

—249—AVS 分像素运动估计优化算法杨涵悦 1&#xff0c;张兆杨1&#xff0c;滕国伟2(1. 上海大学通信学院&#xff0c;上海 200072&#xff1b;2. 上海广电(集团)有限公司中央研究院&#xff0c;上海 200233)摘要&#xff1a;针对AVS 分像素运动估计的问题&#xff0c;提出一种…

计算机系统结构sw指令集,自考02325计算机系统结构复习资料六

自考生网为考生收集整理了“自考02325计算机系统结构复习资料六“以供考生们在考试前用复习资料巩固所学到的知识&#xff0c;得到更好地复习效果。注&#xff1a;由于各省教材每年都有更新、变动&#xff0c;自考复习资料并不一定出于同一自考教材版本&#xff0c;但考生们仍可…