jwt
JWT (JSON Web Token)
(1) JWT简介
什么是JWT
- JWT是一种基于 Token 的****认证授权机制.
- JWT (JSON Web Token) 是目前最流行的跨域认证解决方案,是一种基于 Token 的认证授权机制。从 JWT 的全称可以看出,JWT 本身也是 Token,一种规范化之后的 JSON 结构的 Token。
JWT有什么用
- JWT最常见的场景就是授权认证,用户登录之后,后续的每个请求都将包含JWT, 系统在每次处理用户请求之前,都要先进行JWT的安全校验,通过校验之后才能进行接下来的操作.
JWT认证方式
- JWT通过数字签名的方式,以JSON对象为载体,在用户和服务器之间传递安全可靠的信息.
- 首先,前端通过Web表单将自己的用户名和密码发送到后端的接口。这一过程一般是一个HTTP POST请求。建议的方式是通过SSL加密的传输(https协议),从而避免敏感信息被嗅探。
- 后端核对用户名和密码成功后,将用户的id等其他信息作为JWT Payload(负载),将其与头部分别进行Base64编码拼接后签名,形成一个JWT(Token)。形成的JWT就是一个形同lll.zzz.xxx的字符串。 token head.payload.singurater
- 后端将JWT字符串作为登录成功的返回结果返回给前端。前端可以将返回的结果保存在localStorage或sessionStorage上,退出登录时前端删除保存的JWT即可。
- 前端在每次请求时将JWT放入HTTP Header中的Authorization位。(解决XSS和XSRF问题) HEADER
- 后端检查是否存在,如存在验证JWT的有效性。例如,检查签名是否正确;检查Token是否过期;检查Token的接收方是否是自己(可选)。
- 验证通过后后端使用JWT中包含的用户信息进行其他逻辑操作,返回相应结果。
(2) JWT的组成部分
头部(Header)
- 描述 JWT 的元数据,定义了生成签名的算法以及 Token 的类型。
1 | {"typ":"JWT","alg":"HS256"} |
JWT签名算法中,一般有两个选择,一个采用HS256,另外一个就是采用RS256
进行BASE64编码https://base64.us/,编码后的字符串如下:eyJhbGciOiJIUzI1NiJ9
Base64编码:一个对象先由ascii码转化为二进制(7个二进制一组),然后再将它们以6个为一组(不足用0补齐),然后转化为十进制,再通过十进制的数字和base64的码值表相互转换得到对应的字符,最后的base64的结果需要是4的倍数,不足用=补齐
载荷(payload)
载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分
1 | {"sub":"1234567890","name":"John Doe","admin":true} |
将上面的JSON数据进行base64编码,得到Jwt第二部分: eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
字段说明,下面的字段都是由 JWT的标准所定义的
1 | iss: jwt签发者 |
签名(signature)
服务器通过 Payload、Header 和一个密钥(Secret) 使用 Header 里面指定的签名算法(默认是 HMAC SHA256)生成。
Signature 部分是对前两部分的签名,作用是防止 Token(主要是 payload) 被篡改。
这个签名的生成需要用到:
- Header + Payload。
- 存放在服务端的密钥(一定不要泄露出去)。
- 签名算法。
例如,如果要使用HMAC SHA256算法,则将通过以下方式创建签名:
1 | String encodeString = base64UrlEncode(header) + "." + base64UrlEncode(payload); |
签名用于验证消息在此过程中没有更改,并且对于使用私钥进行签名的令牌,它还可以验证JWT的发送者是它所说的真实身份。
注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
(3) 签名的目的
最后一步签名的过程,实际上是对头部以及载荷内容进行签名。
一般而言,加密算法对于不同的输入产生的输出总是不一样的。对于两个不同的输入,产生同样的输出的概率极其地小(有可能比我成世界首富的概率还小)。所以,我们就把“不一样的输入产生不一样的输出”当做必然事件来看待吧。
所以,如果有人对头部以及载荷的内容解码之后进行修改,再进行编码的话,那么新的头部和载荷的签名和之前的签名就将是不一样的。而且,如果不知道服务器加密的时候用的密钥的话,得出来的签名也一定会是不一样的。
服务器应用在接受到JWT后,会首先对头部和载荷的内容用同一算法再次签名。那么服务器应用是怎么知道我们用的是哪一种算法呢?别忘了,我们在JWT的头部中已经用 alg
字段指明了我们的加密算法了。
如果服务器应用对头部和载荷再次以同样方法签名之后发现,自己计算出来的签名和接受到的签名不一样,那么就说明这个Token的内容被别人动过的,我们应该拒绝这个Token,返回一个HTTP 401 Unauthorized响应。
(4) JWT与Token的区别
Token 和 JWT (JSON Web Token) 都是用来在客户端和服务器之间传递身份验证信息的一种方式。但是它们之间有一些区别。
- Token 是一个通用术词,可以指代任何用来表示身份的字符串。它可以是任何形式的字符串,并不一定是 JWT。
- JWT 是一种特殊的 Token,它是一个 JSON 对象,被编码成字符串并使用秘密密钥进行签名。JWT 可以用来在身份提供者和服务提供者之间安全地传递身份信息,因为它可以被加密,并且只有拥有秘密密钥的方能解密。
总的来说,JWT 是一种特殊的 Token,它具有更强的安全性和可靠性。
(5) JWT的优势
- 简洁(Compact): 可以通过URL,POST参数或者在HTTP header发送,因为数据量小,传输速度也很快
- 自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次查询数据库
- 因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持。
- 不需要在服务端保存会话信息,特别适用于分布式微服务。