JWT(Json Web Token)原理讲解
JWT简单原理
JWT的原理是服务器通过用户认证以后, 会生成一个JSON对象响应给用户.
简单示例:
| |
之后用户与服务端通信的时候, 都要携带这个JSON对象.
服务器完全只靠这个对象认定用户身份.
为了防止数据被篡改, 服务器在生成这个对象的时候, 会加上签名.
服务器不用再保存任何Session数据, 服务器变成无状态的了, 从而可以比较容易实现服务器扩展.
JWT基本流程
用户通过用户名和密码登录系统, 发出登录请求
服务端收到请求数据, 通过查询数据库中的用户名和密码对用户身份进行验证
服务端验证通过后, 为该用户生成
Token, 响应给用户用户将
Token保存起来, 如果使用的是浏览器, 一般自动保存到Cookies(Application-Storage-Cookies)中; 用户之后的请求需携带该Token, 如果用户使用的是浏览器, 一般浏览器会自动通过请求头Authorization: Bearer $token携带该Token进行请求.服务端收到请求后, 首先验证
Token, 通过后返回数据, 没通过返回验证失败信息
注意:
服务端不需要保存Token, 只需要对Token中携带的各种信息进行验证即可, 验证过程一般为:
通过携带的加密算法信息和服务端保存的密钥实时计算签名, 然后和Token的签名(Token的第3个字段)进行比对看Token是否正确、 通过携带的过期时间信息和当前时间比对验证是否过期等.
无论用户访问服务端的哪台服务器, 只要可以通过Token验证即可.
JWT数据结构
服务器为用户生成的Json Web Token示例:
| |
这是一个很长的字符串, 中间用点.分隔成三个部分:
| |
Header(头部)
Header部分是一个JSON对象, 描述JWT的元数据:
| |
alg属性表示签名的算法(algorithm), 默认是HMAC SHA256(通常写成HS256).
typ属性表示这个令牌(token)的类型(type), JWT令牌固定写为JWT.
最后将该JSON对象使用Base64URL算法转成字符串, 就是上面JWT示例的第一个部分.
Payload(装载的内容)
Payload部分也是一个JSON对象, 用来存放实际需要传递的数据.
JWT规定了7个官方字段, 供选用:
| |
除了官方字段, 你还可以在这个部分定义私有字段, 比如:
| |
这个JSON对象同样使用Base64URL算法转成字符串, 就是JWT示例的第二部分.
注意:
JWT默认是不加密的, 任何人都可以读到, 所以不要把私密信息放在这个部分.
Signature(签名)
Signature部分是对前两部分的签名, 用来防止数据被篡改.
首先, 服务端需要自定义一个密钥(secret), 一般是写在配置文件中, 不能泄露给用户.
然后, 使用Header里指定的签名算法(默认是HMAC SHA256), 按照下面的公式产生签名:
| |
算出签名以后, 把Header、Payload、Signature 三个部分使用.号分隔拼成一个字符串, 这个字符串就是JWT(Json Web Token), 然后响应给用户.
Base64URL算法
Header和Payload转换为字符串的算法是Base64URL.
这个算法跟Base64算法基本类似, 但有一些小的不同.
JWT作为一个令牌(token), 有些场景下用户可能会将它作为请求URL的参数,
比如: https://yourapipath/?token=xxx.
由于Base64有三个字符+、/和=, 在URL里面有特殊含义, 所以需要被替换掉:
=被省略、+替换成-, /替换成_, 这就是 Base64URL 算法.
JWT的使用方式
用户收到服务器返回的JWT, 需要保存起来, 如果客户端是浏览器一般会储存在Cookie里面或localStorage.
此后, 用户每次与服务器通信, 都要带上这个JWT, 有几种方式携带JWT:
- 放在
HTTP请求头Cookie里(不能跨域) - 放在
HTTP请求头Authorization里:
| |
- 放在
POST请求的数据体里面
用户如果使用浏览器请求, 浏览器会自动通过HTTP请求头携带JWT进行请求.
JWT的特点和注意事项
JWT默认是不加密的, 但也是可以加密的, 生成Token以后, 可以用密钥再加密一次.JWT在不加密的情况下, 不要将私密数据写入JWT.JWT不仅可以用于认证, 也可以用于交换信息. 有效使用JWT, 可以降低服务器查询数据库的次数.JWT的最大缺点是无法在使用过程中废止某个用户的JWT, 或者更改JWT的权限. 一旦JWT签发了, 在到期之前就会始终有效, 除非服务器部署额外的逻辑.JWT本身包含了认证信息, 一旦泄露任何人都可以获得该令牌的所有权限. 为了减少盗用,JWT的有效期应该设置的比较短. 对于一些比较重要的权限, 即使JWT没有过期也应该再次对用户进行认证(查询数据库进行用户名密码校验).安全原因,
JWT不应该使用HTTP协议明文传输, 要使用HTTPS协议传输.
JWT适用场景
JWT适用于:
App和Web的单页面应用, 比如各种前后端分离的Web项目.- 供用户程序调用的
API项目.
注意:
由后端渲染HTML页面的场景(MVC架构), 建议使用Cookie-session方式认证.