JWT之token机制与双token详解
token机制
何为token
token即为令牌,是服务器生成的一串字符串,作为客户端向服务器进行请求的“通行证”。在客户端进行初次登陆后由服务器返回,之后的每次请求只需要携带token进行请求即可,而无需携带密码等敏感信息
为何token
- token可以减少敏感信息在网络间的传递
- 因为json的通用性,所以JWT是可以进行跨语言支持的,像JAVA,JavaScript,NodeJS,PHP等很多语言都可以使用
- JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息
- 便于传输,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的。它不需要在服务端保存会话信息, 所以它易于应用的扩展
基于token的登录流程
基于token的请求流程
token的结构
先来看看生成的jwt token的样子:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MTA1NDcyMzQsImRhdGEiOiJkYXRhIiwiaWF0IjoxNjEwNTQwMDM0fQ.Qno5UbhzAvlN6QAXpbqpOkeTMt4qEQvmY50Yh87JD74
token分为3个部分,每个部分由一个字符 “ . ”相连:
第一部分(头部/header):
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
头部与http的头部差不多作用,是用来存放声明信息的,其主要有:
{"typ": "JWT", // 这里声明了类型,即JWT"alg": "HS256" // 这里声明了加密算法,即HS256加密算法 }
在头部信息确定好之后,将这些信息经过base64加密,构成了如上所示的token第一部分
第二部分(载荷/payload):
eyJleHAiOjE2MTA1NDcyMzQsImRhdGEiOiJkYXRhIiwiaWF0IjoxNjEwNTQwMDM0fQ
载荷同http的body差不多功能,用来存放有效信息的,其中包含的信息字段种类及其含义如下:
{exp, // 过期时间,这个过期时间必须要大于签发时间iat, // 签发时间[data,] // 如果你想的话,可以塞一些非敏感信息[iss,] // 签发者[sub,] // 面向的用户[aud,] // 接收的一方[nbf,] // 定义一个时间,即在该时间之前,这个jwt是不可用状态[jti] // 唯一身份标识,主要用来作为一次性token,从而回避重放攻击 }
在载荷的信息确定好之后,将这些信息经过base64加密,构成了如上所示的token第二部分
第三部分(签证/signatrue):
Qno5UbhzAvlN6QAXpbqpOkeTMt4qEQvmY50Yh87JD74
签证信息由3个部分组成:
- 上文所述加密后的token第一部分
- 上文所述加密后的token第二部分
- 自定义的混淆字符串
上述3个部分经过指定算法加密之后输出的字符串就构成了如上所示的token第三部分
通俗的来讲就是第三部分是个大杂烩,把上述3个部分丢到加密算法这个大锅里煮(加密),煮出来的菜就是第三部分
自定义的混淆字符串是很重要的部分,需要好好保存在服务端,生成与验证token就靠它了
token注意事项
- 由于token的组成关系,前2部分只用了base64这种可以随意解密的东西加密的,而第三部分作为凭证留在了客户端,因此,token里不能存储敏感信息
双token验证机制
场景设置
在基于token验证登录态这个情境下,可以想象一个场景,你在使用app或者在网页上进行操作时,你的token突然就过期了,然后只好被迫停止现在正在进行的操作跳转到登录页进行重新登录操作,这就非常的智熄了,这带给用户,特别是经常使用或正在进行某个操作的用户,一种非常不好的体验。这就是单token验证登录的一个缺点。因此对于经常/正在使用或经常/正在进行操作的用户(我称之为活跃用户)就不应当跳转到登录页面进行登陆操作(除了某些敏感系统或包含敏感信息进行敏感操作的网页、app、系统),对于这个缺点的解决,这里介绍一个双token的验证机制
ps:或许会有人说可以把token的有效期设的很长啊,但是记住,千万别那么做,这会让token的安全性变得无法保证,在我的理解中,token本就是为了减少未经保护的敏感信息在网络中的传递而设置的,同时也方便了登录态的检验,但是如果token设置的过期时间相当的长,那么token和帐号的安全性变得几乎没有意义,只要任何一个人拿到了token,就可以在一个相当长的时间内对你的帐号动手动脚(怎么一股NTR的味道···?)
何为双token验证
顾名思义,就是在登陆操作之后由服务端返回两个token:accessToken和refreshToken,在之后的验证登录态的操作中使用这两个token进行验证,其中accessToken的过期时间相当短,refreshToken的过期时间相对于accessToken而言相当长,且会不断的刷新,每次刷新后的refreshToken都是不同的
双token验证的优点
通过上面的描述也可以或多或少的看出双token验证机制的优点了:
- accessToken的存在,保证了登录态的正常验证,因其过期时间的短暂也保证了帐号的安全性
- refreshToekn的存在,保证了用户(即使是非活跃用户)无需在短时间内进行反复的登陆操作来保证登录态的有效性,同时也保证了活跃用户的登录态可以一直存续而不需要进行重新登录,其反复刷新也防止某些不怀好意的人获取refreshToken后对用户帐号进行动手动脚的操作(拒绝NTR.jpg)
双token检验流程
首先进行正常的登录操作,在后台服务器验证账号密码成功之后返回2个token:accessToken和refreshToken。在进行服务器请求的时候,先将Token发送验证,如果accessToken有效,则正常返回请求结果;如果accessToken无效,则验证refreshToken。此时如果refreshToken有效则返回请求结果和新的accessToken和新的refreshToken。如果refreshToken无效,则提示用户进行重新登陆操作。
流程图如下:
token的时间设置
token的时间设置需要看需求进行划分区别设置:
PC网络应用
对于网络应用程序而言,由于token可以直接直观地获取到,因此不管是accessToken还是refreshToken为了安全起见,其过期时间都不应该设置得很长,且需要不停地更换token,因此PC网络应用的accessToken一般设置为2h过期,而refreshToken设置为1天到2天比较好,不足1天也是可以的,如果设置的时间比较短就在活跃期间时常刷新freshToken就好了,如果设置的时间比较长,就只需要设置一个阈值(比如7day的refreshToken设置一个6day阈值),在refreshToken小于等于这个阈值的时候就进行刷新refreshToken就好了。
手机应用
对于手机APP应用而言,登录操作一般只做一次,因此token的过期时间必是无限,即不会过期,不过为了安全起见(比如防止你丢手机),token应该以某种程度上对用户可见(比如在安全中心里检验了身份之后可以让你看到哪些设备有token,即哪些设备会被允许登录)并可让用户对其进行一定程度上的操作(比如你手机丢了,然后登录安全中心移除那个手机的token,也就是移除那个手机的登陆权限,从而使那个手机的应用上的你的帐号强制下线)
无效的Token的处理
对于频繁更换的Token,如何处理旧的未过期的而又无效的refreshToken,以下提供了几个思路:
1) 简单地从浏览器中移除token就好了
显然,这种方式对于服务器方面的安全而言并没有什么卵用,但它能通过移除存在的token来阻止攻击者(比如,攻击者必须在用户下线之前窃取到token)
2) 制作一张token黑名单
在移除了浏览器存储的token后如果还想要再严格点,就只能在服务器上制作一张已经无效但是没过期的token的黑/白名单了,在每次请求中都操作数据库进行token的匹配,并以某种方式进行维护(不管是黑名单的定期删除维护也好,白名单的无效时删除也好),不过显然这种方式还是违背了token无状态的初衷,但是除此之外也没别的办法。
存储可以按照userId—token的方式存储在数据库中(当然也可以按你喜欢添加其他字段标明其他信息,比如说mac地址啦,是手机还是电脑啦,设备型号啦,巴拉巴拉巴拉····),白名单的话直接存储有效的token,在需要token无效的逻辑中删除指定token即可(比如刷新token的时候把旧的无效的但未过期的删掉)。而如果是黑名单的话就需要你定期去删除其中已经过期的token了。
而验证的话除了要去数据库名单里匹配之外还需要验证token本身的有效性。
3)只需要将token的过期时间设置的足够短就行了
JWT之token机制与双token详解相关推荐
- Laravel使用Dingo API+JWT实现认证机制 无痛刷新Token
Laravel使用Dingo API+JWT实现认证机制 无痛刷新Token 一.安装[Dingo API](https://github.com/dingo/api) 和 [JWT](https:/ ...
- 第43课: Spark 1.6 RPC内幕解密:运行机制、源码详解、Netty与Akka等
第43课: Spark 1.6 RPC内幕解密:运行机制.源码详解.Netty与Akka等 Spark 1.6推出了以RpcEnv.RPCEndpoint.RPCEndpointRef为核心的新型架构 ...
- 【JVM】Java垃圾回收机制(GC)详解
Java垃圾回收机制(GC)详解 一.为什么需要垃圾回收? 如果不进行垃圾回收,内存迟早都会被消耗空,因为我们在不断的分配内存空间而不进行回收.除非内存无限大,我们可以任性的分配不回收,但是事实并非如 ...
- linux内存管理机制以及free命令详解
linux内存管理机制以及free命令详解 一.linux内存管理机制 1.物理内存和虚拟内存 直接从物理内存读写数据要比从硬盘读写数据要快的多,因此,我们希望所有数据的读取和写入都在内存完成,而内存 ...
- Mapreduce源码分析(一):FileInputFormat切片机制,源码详解
FileInputFormat切片机制,源码详解 1.InputFormat:抽象类 只有两个抽象方法 public abstract List<InputSplit> getSplits ...
- 基于spring security实现vue2前后端分离的双token刷新机制(完整代码详解,含金量拉满!)
目录 一.前言: 核心功能概要: 通过加密算法创建一个用户: 二.后端 代码详解: 1.代码整体结构: 2.所需依赖: 3.UserDetailServiceImpl拦截用户登陆: 4.所需工具类 4 ...
- 模块化封装 --- 双ToKen 实现免登录步骤详解
本文大概配置了下 双token免登录 关于下文提到的store中封装的保存token的方法,请参考本链接: /*** 封装 axios 请求模块*/ import axios from 'axios' ...
- 奥塔在线:基于token认证的基础知识详解
一. 什么是Token Token原始的意思是"令牌",是服务端生成的一个自定义字符串,作为客户端进行数据请求的一个标识.在区块链兴起后,Token被赋予"代币&q ...
- tushare pro的token凭证码设置教程详解
获取tushare pro 的token 首先进入tushare pro官网注册自己的账号,然后点击右上角的个人信息进入下图页面 点击端口TOKEN查看自己的TOKEN,并复制使用. 程序中设置tok ...
最新文章
- 各种函数调用约定及浮点数传参
- Activity的启动模式与flag详解
- ByteTrack 多目标跟踪 测试笔记
- spirng 如何把404转到特定的页面展示
- umask详解、cwd简介
- 多项式相关操作学习笔记
- js获取Json对象的长度
- 论文阅读 - TransNet and TransNet V2
- Asynchronous(异步处理)
- mysql in从数据库取数_MySQL数据库中 where in 用法详解
- Android:复杂listview条目
- 【python】Django设置SESSION超时时间没有生效?
- final关键字多态
- 小i机器人伴侣_【数据分析】2020年3月全国工业机器人产量统计数据分析
- Snap7 西门子S7系列PLC的通信库 简介
- 爆肝三天,我整理了这份春招攻略【针对大三/研二】
- SQL解密ctext字段内容函数
- 【微机原理】8088/8086CPU引脚
- adguard自定义_openwrt上装adguard以及实用教程
- froyo 新的多媒体框架 stagefright与opencore对比
热门文章
- python英语查询词典-随堂作业
- 英文wiki技术基础问题查询的常见问题
- sio_socket, websocket的使用与封装
- php下载 微信头像图片_php微信公众号开发,获取用户头像,并下载
- 2020最后1天朋友圈文案短句_2020余额不足,2021转账成功
- 【2016ACM/ICPC亚洲区大连站C】HDU - 5973 Game of Taking Stones 威佐夫博弈
- OllyDbg的简单使用
- 空间金字塔池化Spatial Pyramid Pooling
- C# 字符串去除制表符回车符换行符
- RK3399平台开发系列讲解(硬件波形解析篇)10.1、USB2.0相关硬件波形(实图)解析