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 完成了一套前后端分离的基础项目,这里把它开源出来分享给有需要的小伙伴们 功能很简单,单点登录,前后端动态权限配 ...
随机推荐
- PHP实现上传文件到服务器
<?php /**************************** *** 功能:上传文件到服务器 ****************************/ session_start() ...
- 并行开发 8.用VS性能向导解剖你的程序
原文:8天玩转并行开发——第八天 用VS性能向导解剖你的程序 最后一篇,我们来说说vs的“性能向导",通常我们调试程序的性能一般会使用Stopwatch,如果希望更加系统的了解程序,我们就需 ...
- 记录使用node启用微信公众平台服务器配置
在微信公众平台的基本信息里面的,修改服务器配置后会有下面的界面. EncodingAESKey是随机生成的,加密方式根据需要自己选择. 关于URL和Token: URL:填写之后会向这个URL发送一个 ...
- Beta阶段成果展示——第八组
Beta阶段成果展示 游戏公网IP:http://119.29.32.204/krad.html(欢迎大家测试!) Beta阶段体现在成果上的工作主要为界面美化,玩家引导,按键封闭等等. 本文将以截图 ...
- skiasharp在阿里云Windows server 2016上部署时提示The type initializer for 'SkiaSharp.SKAbstractManagedStream' threw an exception. 错误
应用环境及问题描述: Windows Server 2016,.Net core 2.1, Skiasharp作为跨平台的图像处理组件在生成缩略图时出错,本地测试都是正常的,部署到服务器无法生成缩略图 ...
- shell脚本实现ftp上传下载文件
前段时间工作中需要将经过我司平台某些信息核验数据提取后上传到客户的FTP服务器上,以便于他们进行相关的信息比对核验.由于包含这些信息的主机只有4台,采取的策略是将生成的4个文件汇集到一个主机上,然后在 ...
- HTML基础:<a>标签 编写个人收藏夹
编写个人收藏夹 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <t ...
- Vue:替换/合并现有的特性
假设这是 bs-date-input 的模板: <input type="date" class="form-control"> 为了给该日期选择器 ...
- runltp出现问题 [
runltp 623行: if [ "$?" == "0" ]; then 对[解析出了问题. 我灵机一动,是不是sh的问题. which sh /bin/sh ...
- 如何解决拖拽或者缩放、移动中的组件canvas有残留情况
当我们在做某些需求,如要拖动echarts图表,或者放大缩小 这个时候,有时连续操作,或者在ie或者内存只有8G的电脑上就会出现canvs残留的情况 我们移动的时候,使用的是transform去做的移 ...