token出现的背景
以前,Web 基本上就是文档的浏览而已,每次请求都是一个新的HTTP协议, 就是请求加响应,尤其是我不用记住是谁刚刚发了HTTP请求
随着交互式Web应用的兴起,像在线购物网站,需要登录的网站等等,面临一个问题,必须记住哪些人登录系统,也就是说我必须把每个人区分开,这就是一个不小的挑战,因为HTTP请求是无状态的,起初想出的办法就是给每一个人发一个唯一的sessionid(一个随机的字符串),下次大家再向我发起HTTP请求的时候,把这个sessionid带着, 这样我就能区分开谁是谁了
每个人只需要保存自己的session id,而服务器要保存所有人的session id !这对服务器说是一个巨大的开销, 严重的限制了服务器扩展能力, 比如说我用两个机器组成了一个集群, 小F通过机器A登录了系统, 那session id会保存在机器A上, 假设小F的下一次请求被转发到机器B怎么办? 机器B可没有小F的 session id啊。
那只好做session 的复制了, 把session id 在服务器之间搬来搬去, 快累死了
于是有人就一直在思考, 我为什么要保存这可恶的session, 只让每个客户端去保存该多好?
可是如果不保存这些session id , 怎么验证客户端发给我的session id 的确是我生成的呢? 如果不去验证,我们都不知道他们是不是合法登录的用户, 那些不怀好意的家伙们就可以伪造session id , 为所欲为了。
关键点就是验证 !
比如说, 小F已经登录了系统, 我给他发一个令牌(token), 里边包含了小F的 user id, 下一次小F 再次通过Http 请求访问我的时候, 把这个token 通过Http header 带过来
不过这和session id没有本质区别啊, 任何人都可以可以伪造, 所以我得想点儿办法, 让别人伪造不了。
那就对数据做一个签名吧, 比如说我用HMAC-SHA256 算法,加上一个只有我才知道的密钥, 对数据做一个签名, 把这个签名和数据一起作为token , 由于密钥别人不知道, 就无法伪造token了
这个token服务器不保存,当小F把这个token 给我发过来的时候,我再用同样的HMAC-SHA256 算法和同样的密钥,对数据再计算一次签名, 和token 中的签名做个比较, 如果相同, 我就知道小F已经登录过了,并且可以直接取到小F的user id , 如果不相同, 数据部分肯定被人篡改过, 我就告诉发送者: 对不起,没有认证

解除了session id这个负担, 可以说是无事一身轻, 我的机器集群现在可以轻松地做水平扩展, 用户访问量增大, 直接加机器就行。 这种无状态的感觉实在是太好了
JWT就是token的一种具体实现方式
JWT本质就是一个字符串,将用户信息存储到一个JSON中,然后编码得到一个JWT token,这个token带有签名信息,服务器接收后可以校验是否被篡改
一个JWT token格式如下所示

他是由.分割的三部分组成,这三部分依次是:
头部(Header):
alg是签名用的算法,默认为HMAC SHA256(写为HS256);
typ属性表示令牌的类型,JWT令牌统一写为JWT。
最后,使用Base64 URL算法将上述JSON对象转换为字符串保存
- {
- "alg": "HS256",
- "typ": "JWT"
- }
负载(Payload):是JWT的主体内容部分,也是一个JSON对象,包含需要传递的数据。 JWT指定七个默认字段供选择
- iss:发行人
- exp:到期时间
- sub:主题
- aud:用户
- nbf:在此之前不可用
- iat:发布时间
- jti:JWT ID用于标识该JWT
除以上默认字段外,我们还可以自定义私有字段,一般会把包含用户信息的数据放到payload中,如下
- {
- "sub": "1234567890",
- "name": "Helen",
- "admin": true
- }
请注意,默认情况下JWT是未加密的,因为只是采用base64算法,拿到JWT字符串后可以转换回原本的JSON数据,任何人都可以解读其内容,因此不要构建隐私信息字段,比如用户的密码一定不能保存到JWT中,以防止信息泄露。JWT只是适合在网络中传输一些非敏感的信息
签名(Signature)
签名哈希部分是对上面两部分数据签名,需要使用base64编码后的header和payload数据,通过指定的算法生成哈希,以确保数据不会被篡改。首先,需要指定一个密钥(secret)。该密码仅仅为保存在服务器中,并且不能向用户公开。然后,使用header中指定的签名算法(默认情况下为HMAC SHA256)根据以下公式生成签名 在计算出签名哈希后,JWT头,有效载荷和签名哈希的三个部分组合成一个字符串,每个部分用.分隔,就构成整个JWT对象
注意JWT每部分的作用,在服务端接收到客户端发送过来的JWT token之后:
header和payload可以直接利用base64解码出原文,从header中获取哈希签名的算法,从payload中获取有效数据
signature由于使用了不可逆的加密算法,无法解码出原文,它的作用是校验token有没有被篡改。服务端获取header中的加密算法之后,利用该算法加上secretKey对header、payload进行加密,比对加密后的数据和客户端发送过来的是否一致。注意secretKey只能保存在服务端,而且对于不同的加密算法其含义有所不同,一般对于MD5类型的摘要加密算法,secretKey实际上代表的是盐值
头部和负载以json形式存在,这就是JWT中的JSON,三部分的内容都分别单独经过了Base64编码,以.拼接成一个JWT Token

token登录过程
token登录对比传统session认证方式的优点如下
1、支持跨域访问:cookie是无法跨域的,而token由于没有用到cookie(前提是将token放到请求头中),所以跨域后不会存在信息丢失问题。
2、无需考虑CSRF(跨站请求伪造):由于不再依赖cookie,所以采用token认证方式不会发生CSRF,所以也就无需考虑CSRF的防御
3、更适用于移动端:当客户端是非浏览器平台时,cookie是不被支持的,此时采用token认证方式会简单很多
4、减轻服务器的压力:token机制在服务端不需要存储session信息,因为token自身包含了所有登录用户的信息,所以可以减轻服务端压力。
JWT(JSON Web Token)
JWT就是上述流程当中token的一种具体实现方式,本质就是一个字符串,它是将用户信息保存到一个Json字符串中,然后进行Base64编码后得到一个JWT token。
流程 : 首先用户输入账号密码后,在服务器进行验证,如果无误的话,在服务器生成通过base64编码生成一个JWT Token(字符串),服务器把这个字符串传给客户端进行本地化存储,退出时删除这个字符串就可以, 前端在每次请求时将JWT Token放入HTTP请求头中的Authorization属性中