Json Web Token (JWT),是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。JWT的声明一般被用来在身份提供者和服务器提供者之间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其他业务逻辑所必须的生命信息,该token可以直接被认证,也可被加密。
说起JWT,我们来谈一谈基于token的认证和传统的session认证的区别
传统的session认证
HTTP协议本身是一种无状态的协议,这意味着如果用户像我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再一次进行用户认证才行,因为根据HTTP协议,我们并不能知道是哪个用户发出的请求,所以为了识别用户,只能在服务器存储一份用户登录信息,这份登录信息就会在响应时传递给浏览器,告诉其保存为cookie,以便下次请求时发送给服务器,这样就能识别来自哪个用户了。
这种基于session的认证使服务器很难得到扩展,随着不同客户端用户的增加,独立的服务器已经无法承载太多的用户,会暴露出session认证的问题,由于服务器存储一份信息,随着用户的增多,服务端的开销会明显增大。服务端做认证记录,如果记录被保存在内存中,这意味着用户下次请求还必须要在请求这台服务器上,这样才能拿到授权的资源,这样的情况,限制了负载均衡器的能力,这也意味着限制了应用的扩展能力。
CSRF:因为基于cookie来进行用户识别,cookie如果被截获,用户就很容易收到跨站请求伪造的攻击。
基于token的鉴权机制
基于token的鉴权机制,它不需要在服务端去保留用户的认证信息或者会话信息,意味着基于token的认证机制的应用不需要考虑用户在哪一台服务器登录了,这就为服务器的扩展提供了便利。
流程上是这样的,
用户使用用户名来请求服务器
服务器进行验证用户的信息
服务器发送一个token给用户
客户端存储token,并在每次请求时附送上这个token
服务器端验证token,并返回数据
这个token要在每次请求时给服务端,它应该被保存在请求头里,另外,服务端要支持CORS策略。
JWT长什么样
JWT是由三段信息构成的,将这三段信息文本连接构成了JWT字符串
JWT的构成,
第一部分,我们称它为头部,第二部分我们称其为载荷,第三部分是签证
JWT的头部承载两部分信息,
声明类型,表示这是jwt信息,
声明加密的算法,
{ 'typ': 'JWT', 'alg': 'HS256' }
然后将头部进行base64,构成了第一部分
payload 载荷
载荷就是存放有效信息的地方,这些信息包含三个部分,
标准中注册的声明 (建议但不强制使用)
iss:jwt签发者,
sub:jwt所面向的用户
aud:接收jwt的用户
exp:jwt的过期时间
nbf:定义在什么时间之前,该jwt都是不可用的 ,
iat: jwt的签发时间
jti:jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
公共的声明
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息,但不建议添加敏感信息。
私有的声明
私有声明是提供者和消费者所共同定义的声明。
定义一个payload
{ "sub": "1234567890", "name": "John Doe", "admin": true }
然后将其进行base64,得到jwt的第二部分
signature
jwt的第三个部分是一个签证信息,这个签证信息由三部分组成
header base64后的
payload base64后的
secret
这个部分需要base64后header和base64后的payload使用,连接组成字符串,然后通过header中声明的加密方式及进行加密,然后就构成了jwt的第三部分。
// javascript var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload); var signature = HMACSHA256(encodedString, 'secret');
// TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
将这三部分用.连接成完整的字符串,就构成了最终的jwt.
注意,secret是保存在服务器端的,jwt的签发发生也是在服务器端,secret就是用来进行jwt的签发和jwt验证,所以,它就是服务器端的私钥,在任何场景下都不应该流露出去,一旦客户知道这个secret,那就意味着客户端可以自我签发jwt了。
整个流程;
服务器上的受保护的路由会检查Authorization header中的JWT是否有效,如果有效,则用户可以访问受保护的资源。如果token是在授权头中发送的,那么跨域资源共享(CORS)将不会成为问题。
JWT与session的差异
它们都是存储用户信息,然而,session是在服务器端的,而jwt是在客户端的。session存储方式的最大问题在于大量占用服务器内存,增加服务器开销。而JWT方式将用户分散到了客户端中,可以明显减轻服务器端压力。
session的状态是存储在服务器端,客户端只有session id;而token的状态是存储在客户端。
基于Token的身份认证是无状态的,服务器或者session中不会存储任何用户细信息。没有会话信息意味着应用程序可以根据需要扩展和添加更多的机器,而不必担心用户登录的位置。用户携带用户名和密码请求访问,服务器校验用户凭据,应用提供一个token给客户端-客户端存储token,并且在随后的每一次请求中都带着它,服务器校验token并返回数据
注意:每一次请求都需要token,token应该放在请求header中,我们还需要将服务器设置为接受来自所有域的请求,用Acess-Control-Allow-Orign:*