基于token的验证
认证、权限和限制
身份验证是将传入请求与一组标识凭据(例如请求来自的用户或其签名的令牌)相关联的机制。然后 权限 和 限制 组件决定是否拒绝这个请求。
简单来说就是:
认证确定了你是谁
权限确定你能不能访问某个接口
限制确定你访问某个接口的频率
认证
REST framework 提供了一些开箱即用的身份验证方案,并且还允许你实现自定义方案。

接下类我们就自己动手实现一个基于Token的认证方案:
自定义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, time
timestamp = 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"] = token
else:
res["code"] = 1
res["error"] = "用户名或密码错误"
return Response(res)
定义一个认证类
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed class MyAuth(BaseAuthentication):
def authenticate(self, request):
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, None
else:
return None, None
视图级别认证
class CommentViewSet(ModelViewSet):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer
authentication_classes = [MyAuth, ]
全局级别认证
# 在settings.py中配置
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ]
}
权限
只有VIP用户才能看的内容。
自定义一个权限类
# 自定义权限
class MyPermission(BasePermission):
message = 'VIP用户才能访问' def has_permission(self, request, view):
"""
自定义权限只有VIP用户才能访问
"""
# 因为在进行权限判断之前已经做了认证判断,所以这里可以直接拿到request.user
if request.user and request.user.type == 2: # 如果是VIP用户
return True
else:
return False
视图级别配置
class CommentViewSet(ModelViewSet):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer
authentication_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 = None
def allow_request(self, request, view):
"""
自定义频率限制60秒内只能访问三次
"""
# 获取用户IP
ip = request.META.get("REMOTE_ADDR")
timestamp = time.time()
if ip not in VISIT_RECORD:
VISIT_RECORD[ip] = [timestamp, ]
return True
history = VISIT_RECORD[ip]
self.history = history
history.insert(0, timestamp)
while history and history[-1] < timestamp - 60:
history.pop()
if len(history) > 3:
return False
else:
return True
def wait(self):
"""
限制时间还剩多少
"""
timestamp = time.time()
return 60 - (timestamp - self.history[-1])
视图使用
class CommentViewSet(ModelViewSet):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer
throttle_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 SimpleRateThrottle
class 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",
}
}
基于token的验证的更多相关文章
- vue & nodejs jwt 的基于token身份验证
现在比较流行的验证方式,是带着token的登录验证 原理 1. 登陆时,客户端发送用户名密码 2. 服务端验证用户名密码是否正确,校验通过就会生成一个有时效的token串,发送给客户端 3. 客户端储 ...
- ArcGIS Server 基于Token安全验证
写在前面:只使用token并不能起到安全验证的作用,ArcGIS Server文件夹的权限是开放的,我们不需要登录Server平台即可访问服务,所以我们应该将Token验证和文件夹的安全性结合起来使用 ...
- ASP.NET Core Web API + Angular 仿B站(三)后台配置 JWT 的基于 token 的验证
前言: 本系列文章主要为对所学 Angular 框架的一次微小的实践,对 b站页面作简单的模仿. 本系列文章主要参考资料: 微软文档: https://docs.microsoft.com/zh-cn ...
- 基于 Token 的身份验证:JSON Web Token(附:Node.js 项目)
最近了解下基于 Token 的身份验证,跟大伙分享下.很多大型网站也都在用,比如 Facebook,Twitter,Google+,Github 等等,比起传统的身份验证方法,Token 扩展性更强, ...
- 基于token的会话保持机制
session简介 做过Web开发的程序员应该对Session都比较熟悉,Session是一块保存在服务器端的内存空间,一般用于保存用户的会话信息. 用户通过用户名和密码登陆成功之后,服务器端程序会在 ...
- WebApi基于Token和签名的验证
最近一段时间在学习WebApi,涉及到验证部分的一些知识觉得自己并不是太懂,所以来博客园看了几篇博文,发现一篇讲的特别好的,读了几遍茅塞顿开(都闪开,我要装逼了),刚开始读有些地方不理解,所以想了很久 ...
- 基于 Token 的身份验证方法
使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录.大概的流程是这样的: 客户端使用用户名跟密码请求登录 服务端收到请求,去验证用户名与密码 验证成功后,服务端会签发一个 Toke ...
- 基于Token的身份验证——JWT
初次了解JWT,很基础,高手勿喷. 基于Token的身份验证用来替代传统的cookie+session身份验证方法中的session. JWT是啥? JWT就是一个字符串,经过加密处理与校验处理的字符 ...
- (转)基于 Token 的身份验证
原文:https://ninghao.net/blog/2834 最近了解下基于 Token 的身份验证,跟大伙分享下.很多大型网站也都在用,比如 Facebook,Twitter,Google+,G ...
随机推荐
- PHP ftp_rename() 函数
定义和用法 ftp_rename() 函数重命名 FTP 服务器上的文件或目录. 如果成功,该函数返回 TRUE.如果失败,则返回 FALSE. 语法 ftp_rename(ftp_connectio ...
- PHP PDO 错误与错误处理
PDO::ERRMODE_SILENT 此为默认模式. PDO 将只简单地设置错误码,可使用 PDO::errorCode() 和 PDO::errorInfo() 方法来检查语句和数据库对象.如果错 ...
- NX二次开发-获取当前part所在路径UF_PART_ask_part_name
#include <uf.h> #include <uf_ui.h> #include <uf_part.h> #include <atlstr.h> ...
- 牛客多校第十场 E Hilbert Sort 递归,排序
题意: 给你一个方阵,再在方阵上给定一些点,按照希尔伯特曲线经过的先后顺序为这些点排序 题解: 定义好比较函数后直接调用排序算法即可. 希尔伯特曲线本来就是用于二维到一维的映射的,因此我们可以考虑对于 ...
- HDU6447 YJJ's Salesman-2018CCPC网络赛-线段树求区间最值+离散化+dp
目录 Catalog Solution: (有任何问题欢迎留言或私聊 && 欢迎交流讨论哦 Catalog Problem:Portal传送门 原题目描述在最下面. 1e5个点,问 ...
- RTC, Real Time Clock
配置 写入RTC_PRL, RTC_CNT, RTC_ALR寄存器时,需要先进入配置模式,通过把RTC_CRL寄存器的CNF位置一. 另外,在每次配置一个寄存器时必须等待上一次配置完成,可以通过检测R ...
- Ulimit 文件配置
cat /etc/security/limits.confsudo vim /etc/security/limits.conf * hard nofile 999999 * soft nofile 9 ...
- 常用sign算法
所有参数包括appkey或者token拼接成&key=value格式 转小写 正序排序 MD5后得到sign
- 一些CSS3新技术
前些日子在SmashingMagazine看到一篇关于CSS3新技术不错的文章,它详细介绍了CSS3的新特性和它的使用方法,它包括:浏览器专有属性.选择器(属性选择器.连字符.伪类.伪元素).RGBA ...
- JS对象 指定分隔符连接数组元素join() join()方法用于把数组中的所有元素放入一个字符串。元素是通过指定的分隔符进行分隔的。
指定分隔符连接数组元素join() join()方法用于把数组中的所有元素放入一个字符串.元素是通过指定的分隔符进行分隔的. 语法: arrayObject.join(分隔符) 参数说明: 注意:返回 ...