了解 JSON Web Token(JWT)

JSON Web Token(JWT)是目前最流行的跨域身份验证(CORS)解决方案。本文介绍 JWT 的原理和用法。
官网地址:戳我

跨域身份验证的问题

Internet 服务离不开用户的身份验证。一般过程如下:

  1. 用户向服务器发送用户名和密码。
  2. 服务器验证通过后,在当前对话(session)中保存相关数据,比如用户角色、登录时间等。
  3. 服务器向用户返回 session_id,写入到用户的 Cookie 中。
  4. 用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。
  5. 服务器收到 session_id 并对比之前保存的数据,由此确认用户的身份。

这种模式最大的问题是,没有分布式架构,不支持横向扩展。如果仅使用一台服务器,该模式完全没有问题。但是,如果是服务器群集,或者是跨域的服务导向架构,则需要一个统一的 session 数据库来实现会话数据共享,这样负载均衡下的每台服务器才可以正确的验证用户身份。

举一个实际中常见的单点登陆需求:站点 A 和站点 B 提供同一公司的相关服务。现在要求用户只需要登录其中一个网站,然后它就会自动登录到另一个网站。怎么做?

一种解决方案是通过持久化 session 数据,写入数据库或文件持久层。所有服务器收到请求后,都从持久层请求数据。该解决方案的优点在于架构清晰,而缺点是架构修改比较费劲,整个服务的验证逻辑层都需要重写,工作量相对较大。而且由于依赖于持久层的数据库或文件系统,会有单点故障的风险,如果持久层发生异常,整个认证体系都会挂掉。

还有一种相对灵活的解决方案,通过客户端保存数据,而服务器根本不保存会话数据,每个请求都被发送回服务器。 JWT 是这种解决方案的代表。

JWT 的原理

JWT 的原理是,服务器的身份验证通过后,生成一个 JSON 对象并将其发送回用户,如下所示:

{
  "UserName": "zhangsan",
  "Role": "Admin",
  "Expire": "2019-07-12 01:57:00"
}

之后,当客户端与服务器通信时,客户端在请求中返回该 JSON 对象。服务器仅依赖于这个 JSON 对象来标识用户身份。为了防止用户篡改数据,服务器将在生成对象时添加签名(有关详细信息,请参阅下文)。

服务器不保存任何会话数据,即服务器变为无状态,使其更容易扩展。

JWT 的数据结构

实际上,一个 JWT 数据类似下图所示:

该对象是一个很长的字符串,字符之间通过 "." 分隔符分为三个子串。注意 JWT 对象为一个长字串,各字串之间也没有换行符,此处为了演示需要,我们特意分行并用不同颜色表示了。每一个子串表示了一个功能块,总共有以下三个部分:

  • Header(JWT 头部)
  • Payload(有效载荷)
  • Signature(签名)

将它们写成一行如下所示:

1. JWT 头

JWT 头是描述 JWT 元数据的 JSON 对象,通常如下所示。

{
  "alg": "HS256",
  "typ": "JWT"
}

上面的代码中:

  • alg 属性表示签名算法,默认为 HMAC SHA256(写成 HS256);
  • typ 属性表示令牌的类型,JWT 令牌统一写为 JWT。

最后,使用 Base64URL 算法将上述 JSON 对象转换为字符串。

2. 有效载荷

有效载荷,是 JWT 的主体内容部分,也是一个 JSON 对象,用来存放实际需要传递的数据。 JWT 指定七个默认字段供选择:

  • iss (issuer):令牌的签发人;
  • exp (expiration time):过期的时间戳,以秒为单位;
  • sub (subject):令牌的主题(很少使用);
  • aud (audience):令牌的受众(很少使用);
  • nbf (Not Before):生效时间,在此之前不可用;
  • iat (Issued At):令牌的签发时间;
  • jti (JWT ID):令牌的唯一标识符,用于防止 JWT 被重复使用或重放;

除以上默认字段外,我们也可以自定义字段类型,如:

{
  "sub": "1234567890",
  "name": "chongchong",
  "admin": true
}

注意,默认情况下 JWT 是未加密的,任何人都可以读取其内容,因此不要把秘密信息放在这个部分,以防止信息泄露。

这个 JSON 对象也会使用 Base64URL 算法转换为字符串。

3. 哈希签名

哈希签名是对前面两部分数据进行签名,通过指定的算法生成哈希值,防止数据被篡改。

首先,需要指定一个密钥(secret)。该密钥仅保存在服务器中,并且不能向用户公开。然后,使用 JWT 头中指定的签名算法(默认情况下为 HMAC SHA256)根据以下公式生成签名:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

在计算出哈希签名后,JWT 头,有效载荷和哈希签名这三部分组合成一个字符串,每个部分用 "." 分隔,就构成了整个 JWT 对象。

4. Base64URL 算法

如前所述,JWT 头和有效载荷序列化的算法中都用到了 Base64URL。该算法和常见 Base64 算法类似,但稍有差别。

作为令牌的 JWT 可能会被放在 URL 中(例如 api.example/?token=xxx)。 而 Base64 中用到的三个字符 "+","/" 和 "=" 在 URL 中有特殊含义,因此 Base64URL 中对他们做了替换:"=" 去掉,"+" 用 "-" 替换,"/" 用 "_" 替换,这就是 Base64URL 算法。

JWT 的使用方式

客户端收到服务器返回的 JWT 后,将其存储在 Cookie 或 localStorage 中。

此后,客户端每次与服务器通信,都要带上这个 JWT。如果将它存储在 Cookie 中,就可以自动发送,但是这样不能实现跨域。因此,一般将它放在 HTTP 请求头(Header)的 Authorization 字段中。

Authorization: Bearer <token>

另一种做法是,当跨域时,将 JWT 放在 POST 请求体中。

JWT 的特点

  1. JWT 默认不加密,但也是可以加密的。生成原始 Token 后,可以用密钥再加密一次。
  2. 没有对 JWT 进行加密时,请不要将秘密数据写入 JWT 中。
  3. JWT 不仅可用于认证,还可用于信息交换。有效使用 JWT,可以减少服务器查询数据库的次数。
  4. JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发,在有效期内将会一直有效,除非服务器部署额外的逻辑。
  5. JWT 本身包含认证信息,因此一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期不宜设置太长。对于某些重要操作,使用时应该再次进行身份验证。
  6. 为了减少盗用,JWT 不建议使用 HTTP 协议来传输,而是使用加密的 HTTPS 协议进行传输。

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容