Jwt的使用场景

什么是Jwt

Jwt是JSON Web Tokens的简称,从单词可以看出它也是一种token,其实可以理解为一种生成token的框架或规范。既然也是token那我们可以换一种问法,token是什么?为什么要使用token?

token是什么

Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。

为什么要使用token

说到这大家可能会想到,用服务器的session_id存储到cookies中也能做到,为什么非要用token呢?网上有许多文章来比较token和session的优缺点,其实笔者觉得,开发web应用的话用哪种都行。但如果是开发api接口,前后端分离,最好使用token,为什么这么说呢,因为session+cookies是基于web的。但是针对 api接口,可能会考虑到移动端,app是没有cookies和session的。

如何实现token

其实token只是一个概念模型,就是为了方便用户不用每次访问页面都输入用户名密码来做验证。开发者可以针对自己开发的应用定义自己的token。只要能做到不让黑客或者无聊的人钻系统漏洞即可。设想一下,我们自定义的token只是通过简单的MD5加密,一个黑客很容易找到token的加密规则,那么他就可以伪造其他用户登陆的token,可以随意的获取数据了。所以个人自定义的token,没有太多的加密经验,还是很不安全的。再者,自己定义token加密解密规则无形增加了工作量,有现成的为什么不用呢?

通过对token的模型总结,jwt作者总结了一套比较完善的token生成方案,它的加密方式非常安全,可以方便用户生成自己token。那么我们就看下jwt的组成。

上图中,左半部分是生成的token,右半部分是加密前的明文。分为三部分:header,payload,verify signature。

header:用户存储加密方式,图中的加密方式是HS256,这种加密方式使用相同的密钥,相比RSA安全性低一点,一般都使用RSA非对称加密,具体的加密方法可搜索RSA加密。

payload:是属于内容部分,就是存储我们要保存到客户端的信息,一般都是包含用户的基本信息,权限信息,时间戳等信息。

verify signature:签名哈希部分是对上面两部分数据签名,通过指定的算法生成哈希,以确保数据不会被篡改。

首先,需要指定一个密码(secret)。该密码仅仅为保存在服务器中,并且不能向用户公开。然后,使用标头中指定的签名算法(默认情况下为HMAC SHA256)根据以下公式生成签名。
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload),secret)
在计算出签名哈希后,JWT头,有效载荷和签名哈希的三个部分组合成一个字符串,每个部分用"."分隔,就构成整个JWT对象。
以上三部分都是在服务器定义,当用户登陆成功后,根据用户信息,按照jwt规则生成token返回给客户端。

整体的流程

无状态token:无状态token就是服务器不保存token信息,当用户登陆成功后,返回用户token,用户通过cookies或者本地存储方式保存起来,以后用户每次访问服务器都带着这个token,服务器会先根据jwt规则验证token的有效性,如果有效则让用户继续访问对应接口,如果无效则返回提示信息。

可能有人会问,无状态token如何处理过期时间呢?难道可以使用到3000年吗?这个问题可以通过token中的时间戳来解决。比如用户登陆成功的时间是2019年7月1日。那么token的时间戳字段就赋值为2019/07/01。根据需求,假如默认用户30天token过期。那么用户每次访问服务器做权限验证时,就可以验证时间戳信息,用当前服务器时间减去时间戳时间,如果大于30天就提示用户token失效,请重新登陆。

那么有些人可能还会问,如果服务器管理员注销了该用户,但是该用户用之前登陆的token是否还是可以访问系统呢?这个可以通过在服务器建立一个注销用户表,在验证jwt信息时,去注销用户表查询是否有该用户,如果存在的话就禁止用户访问了。当然,解决方案不知这么一种,还是看开发者实际的需求而定。

有状态token:有状态token就是服务器保存token信息,跟web中的session实现很像。通过上边的介绍可能会觉得无状态token挺省事的,为什么还需要有状态token呢? 通过前边jwt的介绍,我们会发现,jwt的内容还是比较长的,每次客户端访问服务器都携带这么长的信息,频繁的访问服务器还是比较耗费时间和流量的。尤其在jwt的payload中存储比较多的用户信息及权限信息。token的长度会非常长。

那如何解决这个问题呢?这就要引入有状态token,我们可以想像下传统服务器session的实现,它只把session_id存储到客户端,客户端频繁访问服务器只携带session_id,然后服务器通过session_id去session中查找对应的存储信息。有状态token也是使用这个逻辑:在用户第一次登陆成功后,服务器生成jwttoken,因为jwttoken比较长,遂将其存在了服务器,然后返回客户端一个加密的tokenid,客户端每次通过这个加密的tokenid访问服务器,原理就跟session_id的流程是一样的了。

我们知道服务器的session是存储在内存中的,为了高效。同理我们将jwttoken信息也存储在服务器的内存,通用的解决方案是存储到redis中,我们知道redis的存储是基于内存的。速度会比数据库快一些(当搭建集群后redis显得尤为重要,分布式session就是通过redis解决的)。

所以总结下,有状态token的流程。客户端第一次登陆成功,服务器生成jwttoken信息,并将该信息存储到redis中,然后返回tokenid给客户端,客户端通过cookies或者本地存储保存tokenid,以后每次访问都会携带该tokenid。服务器接收到请求后,先通过tokenid去redis中查询出jwttoken信息,然后对jwttoken信息做验证。验证成功执行相应后续操作。

有状态token的过期时间是如何解决的呢?基于redis存储,解决这个问题就很简单了,因为redis是可以设置数据的有效时间的,假如有效期为30天,在插入数据时,就可以设置该条数据的有效期为30天,30天后,redis就会自动删除该数据。那么30天后,用户携带tokenid来访问服务器,服务器去redis中查询不到信息,代表验证失败。

总结

什么时候使用有状态token,什么时候使用无状态的token呢?通过我们上边的分析不难发现,当token中信息比较少时,可以使用无状态token。当token中信息比较多,还是建议使用有状态token。在实际工作中,使用无状态token还是比较少见的。

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值