Django 利用JWT实现前后端分离的Token验证
一、什么是Token?
Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器会生成一个Token并将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。
二、为什么要使用Token?
在很多项目案例中,需要实现账户的功能,客户端所有的功能都基于用户已登陆的前提下才可以使用。这就要求每次客户端像服务器请求数据时都要验证账户是否正确,如果正确则按正常方式返回数据,如果错误则进行拦截并返回错误信息。但是当客户端频繁向服务器请求数据的话,每次服务器都要频繁地查询数据库。而Token正是为了减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮。并取代传统使用session的方法来进行验证。
三、JWT json-web-token
1.三大组成
1,header
格式为字典,元数据格式如下
{'alg':'HS256', 'typ':'JWT'}
#alg代表要使用的 算法
#typ表明该token的类别 - 此处必须为 大写的 JWT
该部分数据需要转成json串并用base64加密
2,payload
格式为字典,此部分分为公有声明和私有声明
公共声明:JWT提供了内置关键字用于描述常见的问题
此部分均为可选项,用户根据自己需求 按需添加key,常见公共声明如下:
{'exp':xxx, # Expiration Time 此token的过期时间的时间戳
'iss':xxx,# (Issuer) Claim 指明此token的签发者
'aud':xxx, #(Audience) Claim 指明此token的
'iat':xxx, # (Issued At) Claim 指明此创建时间的时间戳
'aud':xxx, # (Audience) Claim 指明此token签发面向群体
}
私有声明:用户可根据自己业务需求,添加自定义的key,例如如下:
{'username': 'guoxiaonao'}
公共声明和私有声明均在同一个字典中;转成json串并用base64加密
3,sign 签名
签名规则如下:
根据header中的alg确定具体算法,以下用 HS256为例
HS256(自定义的key , base64后的header + '.' + base64后的payload)
解释:用自定义的key, 对base64后的header + '.' + base64后的payload进行hmac计算
2,jwt结果格式
base64(header) + '.' + base64(payload) + '.' + base64(sign)
最终结果如下: b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Imd1b3hpYW9uYW8iLCJpc3MiOiJnZ2cifQ.Zzg1u55DCBqPRGf9z3-NAn4kbA-MJN83SxyLFfc5mmM'
3,校验jwt规则
1,解析header, 确认alg
2,签名校验 - 根据传过来的header和payload按 alg指明的算法进行签名,将签名结果和传过来的sign进行对比,若对比一致,则校验通过
3,获取payload自定义内容
4,pyjwt
安装 pip3 install pyjwt
| 方法 | 参数说明 | 返回值 |
|---|---|---|
| encode(payload, key, algorithm) | payload: jwt三大组成中的payload,需要组成字典,按需添加公有声明和私有声明 例如: {'username': 'guoxiaonao', 'exp': 1562475112} 参数类型: dict | token串 返回类型:bytes |
| key : 自定义的加密key 参数类型:str | ||
| algorithm: 需要使用的加密算法[HS256, RSA256等] 参数类型:str | ||
| decode(token,key,algorithm,) | token: token串 参数类型: bytes/str | payload明文 返回类型:dict |
| key : 自定义的加密key ,需要跟encode中的key保持一致 参数类型:str | ||
| algorithm: 同encode | ||
| issuer: 发布者,若encode payload中添加 'iss' 字段,则可针对该字段校验 参数类型:str | 若iss校验失败,则抛出jwt.InvalidIssuerError | |
| audience:签发的受众群体,若encode payload中添加'aud'字段,则可针对该字段校验 参数类型:str | 若aud校验失败,则抛出jwt.InvalidAudienceError |
PS: 若encode得时候 payload中添加了exp字段; 则exp字段得值需为 当前时间戳+此token得有效期时间, 例如希望token 300秒后过期 {'exp': time.time() + 300}; 在执行decode时,若检查到exp字段,且token过期,则抛出jwt.ExpiredSignatureError
老师手写的Jwt类,很厉害:
import base64
import copy
import hmac
import json
import time class Jwt(): def __init__(self):
pass @staticmethod
def encode(payload, key, exp=300): #init header
header = {'typ': 'JWT', 'alg': 'HS256'}
#separators - 指定序列化后的json串格式, 第一个参数
#指每个键值对之间的连接符号,第二个参数指的是每一个键值对中键和值之间的连接符号
#sort_keys - 将序列化后的字符串进行排序
header_json = json.dumps(header, separators=(',',':'), sort_keys=True)
#生成b64 header
header_bs = Jwt.b64encode(header_json.encode()) #参数中的 payload {'username': 'aaa'}
payload = copy.deepcopy(payload)
#添加公有声明 - exp 且值为未来时间戳
payload['exp'] = int(time.time()) + exp
payload_json = json.dumps(payload, separators=(',',':'), sort_keys=True)
payload_bs = Jwt.b64encode(payload_json.encode()) #签名
#判断传入的key的类型
if isinstance(key, str):
key = key.encode()
hm = hmac.new(key, header_bs + b'.' + payload_bs, digestmod='SHA256')
hm_bs = Jwt.b64encode(hm.digest()) return header_bs + b'.' + payload_bs + b'.' + hm_bs @staticmethod
def b64encode(j_s):
#替换生成出来的b64串中的占位符 =
return base64.urlsafe_b64encode(j_s).replace(b'=',b'') @staticmethod
def b64decode(b64_s): rem = len(b64_s) % 4
if rem > 0:
b64_s += b'=' * (4-rem)
return base64.urlsafe_b64decode(b64_s) @staticmethod
def decode(token, key):
#校验两次HMAC结果
#检查exp公有声明的有效性
#注意 b64 = 要补全
#校验成功 返回 payload 字典对象, 失败的话 raise
header_b , payload_b , sign = token.split(b'.') if isinstance(key, str):
key = key.encode()
#比较两次HMAC结果
hm = hmac.new(key, header_b + b'.' + payload_b, digestmod='SHA256')
if sign != Jwt.b64encode(hm.digest()):
raise JwtSignError('---sign error !!! ')
#获取payload
payload_json = Jwt.b64decode(payload_b)
payload = json.loads(payload_json.decode())
#校验exp是否过期
exp = payload['exp']
now = time.time()
if now > exp:
#过期
raise JwtExpireError('---The token is expire !!!') return payload class JwtSignError(Exception): def __init__(self, error_msg):
self.error_msg = error_msg def __str__(self):
return '<JwtSignError is %s>'%(self.error_msg) class JwtExpireError(Exception): def __init__(self, error_msg):
self.error_msg = error_msg def __str__(self):
return '<JwtExpireError is %s>' % (self.error_msg) if __name__ == '__main__': s = Jwt.encode({'username':'guoxiaonao'}, 'abcde') #time.sleep(2) #res = Jwt.decode(s, 'abcde')
print(s)
Django 利用JWT实现前后端分离的Token验证的更多相关文章
- SpringBoot20 集成SpringSecurity02 -> 利用SpringSecurity进行前后端分离的登录验证
1 SpirngBoot环境搭建 创建一个SpringBoot项目即可,详情参见三少的相关博文 参考博文 -> 点击前往 SpirngBoot项目脚手架 -> 点击前往 2 引入Spirn ...
- SpringBoot使用SpringSecurity搭建基于非对称加密的JWT及前后端分离的搭建
SpringBoot使用SpringSecurity搭建基于非对称加密的JWT及前后端分离的搭建 - lhc0512的博客 - CSDN博客 https://blog.csdn.net/lhc0512 ...
- 从零玩转SpringSecurity+JWT整合前后端分离
从零玩转SpringSecurity+JWT整合前后端分离 2021年4月9日 · 预计阅读时间: 50 分钟 一.什么是Jwt? Json web token (JWT), 是为了在网络应用环境间传 ...
- 前后端分离使用 Token 登录解决方案
前后端分离使用 Token 登录解决方案:https://juejin.im/post/5b7ea1366fb9a01a0b319612
- Spring Security + JWT实现前后端分离权限认证
现在国内前后端很多公司都在使用前后端分离的开发方式,虽然也有很多人并不赞同前后端分离,比如以下这篇博客就很有意思: https://www.aliyun.com/jiaocheng/650661.ht ...
- 利用gulp解决前后端分离的header/footer引入问题
在我们进行前后端完全分离的时候,有一个问题一直是挺头疼的,那就是公共header和footer的引入.在传统利用后端渲染的情况下,我们可以把header.footer写成两个单独的模板,然后用后端语言 ...
- JWT 在前后端分离中的应用与实践
关于前后端分离 前后端分离是一个很有趣的议题,它不仅仅是指前后端工程师之间的相互独立的合作分工方式,更是前后端之间开发模式与交互模式的模块化.解耦化.计算机世界的经验告诉我们,对于复杂的事物,模块化总 ...
- Shrio使用Jwt达到前后端分离
概述 前后端分离之后,因为HTTP本身是无状态的,Session就没法用了.项目采用jwt的方案后,请求的主要流程如下:用户登录成功之后,服务端会创建一个jwt的token(jwt的这个token中记 ...
- 基于Spring Boot+Spring Security+JWT+Vue前后端分离的开源项目
一.前言 最近整合Spring Boot+Spring Security+JWT+Vue 完成了一套前后端分离的基础项目,这里把它开源出来分享给有需要的小伙伴们 功能很简单,单点登录,前后端动态权限配 ...
随机推荐
- Codeforces - 1194C - From S To T - 子序列 - 排序
https://codeforces.com/contest/1194/problem/C 好像没什么好说的,要能构造s必须是t的子序列,并且相差的字符集合d是p的子集. 用双指针法求两遍子序列就可以 ...
- python学习第十九天三元运算符与php语言区别
三元运算符是条件语句的简写,常见的条件语句写三行,三元运算符只需要写一行,python三元运算符是怎么写的呢 1,常见条件判断 if a<b: print(a) else: print(b) 2 ...
- Vue / keep-alive使用
keep-alive keep-alive是Vue提供的一个抽象组件,用来对组件进行缓存,从而节省性能,由于是一个抽象组件,所以在v页面渲染完毕后不会被渲染成一个DOM元素 <keep-aliv ...
- 找回git rebase --skip消失的代码
1.git reflog操作,查看提交的历史记录,找到自己的提交 2.强制回退到上一次提交:git reset --hard 791a1fc 或者 git reset --hard HEAD@{2 ...
- elasticsearch 深入 —— 全文检索
全文搜索 我们已经介绍了搜索结构化数据的简单应用示例,现在来探寻 全文搜索(full-text search) :怎样在全文字段中搜索到最相关的文档. 全文搜索两个最重要的方面是: 相关性(Relev ...
- Minor GC与Full GC分别在什么时候发生?
Minor GC 当Eden区没有足够空间进行分配时,虚拟机就会进行一次Minor GC 新生代的垃圾收集动作,采用的是复制算法 对于较大的对象,在Minor GC的时候可以直接进入老年代 Full ...
- 【python实例】判断是否是回文数
""" 输入一个数,判断一个这个数是否是回文数.例如:121,这个数反过来还是121,所以这个是回文数: 再如:134,这个数反过来是431,所以这不是一个回文数: 12 ...
- BZOJ2695 保护古迹
非常带劲之计算几何 写的头晕= = 就是平面图转对偶图然后最小割 由于p非常小我们枚举所有保护状态然后割一下 建图真的烦 就是把区域划分出来看一下每一个古迹点是否被小区域包含[好像也可以写点定位] 然 ...
- sublime text 3 快捷操作
快捷键:1.通用 ↑↓← → 上下左右移动光标 Alt 调出菜单 Ctrl + Shift + P 调出命令板(Command Palette) Ctrl + ` 调出控制台 2.编辑 Ctrl + ...
- ES6转ES5环境搭配
1.初始化项目 在项目根目录创建 package.json 文件 npm init //或者 npm init -y 2.安装babel-cli脚手架 npm install babel-cli -- ...