欢迎大家搜索“小猴子的技术笔记”关注我的公众号,有问题可以及时和我交流。
我们知道http是无状态短连接的通信方式,也就是你请求了服务器,服务器响应给你了数据之后连接通信就断开了。这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再一次进行用户认证才行。
传统的session认证:因为http的无状态我们并不能知道是哪个用户发出的请求,所以为了让我们的应用能识别是哪个用户发出的请求。我们只能在服务器存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器并告诉其保存为cookie,以便下次请求时发送给我们的应用,这样我们的应用就能识别请求来自哪个用户了,这就是传统的基于session认证。
那么传统的session认证有什么缺点呢?
第一对服务器的压力大:因为每个用户经过服务器认证之后,服务器都要做一次记录,通常这些记录都是保存在内存中,而随着认证用户的增多,服务器开销会明显增大。
第二程序扩展性变差:用户认证后,服务器做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须在这台服务器上才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力,也就意味着限制了扩展的能力。
第三安全性偏低:因为是基于cookie来进行用户识别的,cookie如果被截获,用户就会很容易受到跨站请求伪造(CSRF)的攻击。
基于token的认证:近些年来基于token的认证开始成为主流,比较简单的token就是使用一个唯一的字符串用来标识是哪个用户,然后把这个字符串token存在Redis中,每次请求的时候拦截,判断Redis中是否有这个token,并做一些处理。
基于JWT的认证:其实JWT也是基于token认证的一种方式。JWT全名叫做Java web token,是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准,可实现无状态、分布式的Web应用授权(官网:https://jwt.io/introduction)。JWT只需要保存在客户端即可,减少了对服务器的压力。JWT的结构由三部分组成:
Header:头部分通常有两部分组成,一个是使用到的签名算法("HS256"是JWT官方比较推荐的签名算法)一个是令牌的类型(这里目前就一种类型JWT)。这个header被base64编码之后就形成了JWT的第一部分(如果不明白什么是base64的话,可以参考我之前的文章《知道你的图片上传为什么不合格吗?》有详细说明哦图片)。
{
"alg": "HS256",
"typ": "JWT"
}
Payload:负载用来存放信息,官网介绍有三部分,这里就先大致理解为存放的是我们需要传递的内容信息,比如“userId, username, age ”之类的信息。需要注意的是,一些敏感的数据不要在这传输,因为token是可以返解密的。然后对负载进行base64编码形成JWT的第二部分。
{
"age": 18,
"name": "John Doe"
}
Signature:创建签名,我们在header中指定了一个秘钥,作用就是用来在创建签名的时候进行加密的。用编码后的header和payload以及秘钥,按照公式进行加密之后得到的数据就是我们需要的JWT。例如文中使用了"HS256"算法。则对应的加密处理就为:
HMACSHA256( base64UrlEncode(header) + “.” + base64UrlEncode(payload), secret)
最终得到数据类似“xxxx.yyyy.zzzz”这个样子,三部分中间使用逗号进行分割。
这里仅仅是简单介绍了JWT的组成,其实JWT还有很多有意思的东西,比如token过期,token刷新机制等。这些在以后的文章中会进行更新。
相比于传统的session,使用JWT可以更轻量,更加简洁,包含的内容也更多。同时还可以支持跨域访问,避免cookie伪造和CSRF攻击。