这是一篇关于 JWT(JSON Web Token) 的简短介绍。

什么是JWT

JWT, 全称是JSON Web Token, 是一种易于使用、无状态的鉴权(Authorization)方式。 简单的来说,就是 Server端把JSON数据经过加密做成token,以授权给Client端

多说无益,上代码,举个栗子。

当Client端登录完成以后, Server端要返回一个7天有效的token, 那么对应的Python的样例代码会是这样的: (使用了PyJWT包:pip install pyjwt

import time

import jwt

exp = int(time.time()) + 86400 * 7  # 失效时间
user = 'liriansu'  # 用户表示
key = 'hunter2'  # 密钥
payload = {'exp': exp, 'user': user}  # JSON 数据
token = jwt.encode(payload, key)

print(token)
# token可能会长这样子
# eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.EoKoMCjq_zGqUg5HDfqw4EN7EiG6gMjkUZle0uGJDGU

关于hunter2也有个梗:弱密码hunter2

然后Client端每次在authorization header或者是query string里带上token。 Server端收到请求的时候, 用payload = jwt.decode(token, key)验证权限就行了。 验证通过以后,payload中就是整个JSON数据。 理论上你可以往token payload里塞任何_非敏感_数据。

所以综合来说, 假如使用JWT作为鉴权方式, 有以下几个特性:

  1. Client端不用管任何加密/解密,只用存token,在请求里面带上就行了。
  2. Server端可以实现不依赖外部存储鉴权,所有的数据都丢在token里。
  3. 也就是说鉴权这一步不需要File/MySQL/Redis之类的数据库,也能知道用户身份。
  4. 因为token带失效时间,所以需要在失效前/后再刷新token。

好了,以上就是关于JWT的所有描述了。 本次的简单介绍就到此结束。(雾) (不过上次关于Hawk的介绍大概就是这样的)

关于JWT的更多说明

讲了这么多,实质上就是用个JSON数据当token, 这破token真的安全吗?能伪造吗?

emmmmmm, 好问题(表示这个问题很尖锐,难以正面回答,准备迂回) JWT使用很广泛,久经考验,大家都在用(表现了我也不懂,应该不会有问题吧?的一种从众心理)

认真地发表一下个人意见: 首先token/key泄漏了, 后果基本是跟其它鉴权方式一样严重。 其次JWT可以选择合适的加密方式, 加上合适的key是基本伪造不了的。 还有就是在JWT之外, 一定要用HTTPS! 不用JWT相当于没有门禁, 不用HTTPS基本是不穿内裤了。。。

我想了解更详细的JWT生成/验证过程

具体说明请参照来源 RFC7519 - JSON Web Token (JWT)

简单的来说,JWT是由以下三部分组成的:

  1. 第一部分指定了加密算法(alg)和token类型(typ)。
  2. 第二部分就是我们定义的payload。
  3. 第三部分是由加密算法产生的签名。

获取了三部分数据以后, 分别用base64加密, 把最末的等号去掉, 再用小数点连在一起, 就是一个token了。 验证的话,基本就是把这个过程反过来。

我去,那token里的信息就是明文的啊?

是的。 所以token里不要带任何敏感信息。

文档上把payload里带的信息叫Claim, 有这么几个可选的Claim

  • iss: Issuer, 签发方。 比如这个token是微信签发的, 那么可以是{'iss': 'wechat'}

  • aud: Audience, 接收方。 比如王者荣耀想用微信登录, 那么可以是{'aud': 'king-of-glory'}

  • exp: Expiration Time, 失效时间。 使用的是整形Unix时间戳, 关于时间戳可以看看《互联网上的日期和时间》

RFC7519里面还有一点很好玩, 就是上面每一个Claim最后都加了一句Use of this claim is OPTIONALRFC2119还定义过啥叫OPTIONAL

也就是说我们可以往payload里丢任何东西。 只要符合这种加密/解密/鉴权的方式, 我们都可以说“我们用了JWT”。

那token会不会很大?

有可能会。

所以payload里的东西能少则少, 看文档里,连issuer -> iss, audience -> aud这种地方都给省了好几个字符。

还有就是传输JWT的时候, 相较于放query string里, 更推荐放在Request Headers里面。

与其他鉴权方式的对比

详尽的比较超越了本文的范畴, (写这句话好爽,可以少查一万个资料) 下面就用个简单的表格来对比一下_我了解的_几种鉴权方式吧: JWT, OAuth, Session, Hawk

  JWT OAuth Session Hawk
易用性 容易,就一个token 麻烦,要用Refresh Token刷Access Token 容易,用Cookie就行 麻烦,每个请求都要单独计算header
泛用性 各种场合都适用 带三方授权的场合特别适用 还行吧… 能用header的都适用
安全性 跟别的方案差不多,key泄漏了就完蛋了 Auth Server安全就行,我才不管Client其它的跟别的方案差不多 还行吧… 我!能!防!中间人攻击!
接受度 有一定安全度,client端很喜欢,用的还是很多的 繁琐和安全的折中方案,很多大厂都用 真的广… 目前只听说了我司在用Hawk

其它感受

  • JWT全称叫JSON Web Token, 小心别写了类似jwt_token这样的变量名了(语义重复)。

  • RFC7519还定义了JWT读起来是类似于jot的发音。 然而实际中交流都会说JWT(怕听不懂)。

  • JWT说是说用同一个key就行了, 不过我们在项目实际中还是根据不一样的user用了不一样的key。 (同时也用了数据库)

  • 假如payload里带了失效时间, 理论上JWT签发后是不会失效的, 也就是Server端管理不了这些token。 (所以可以加个数据库来管) (好像变复杂了)

  • 用JWT想做“记住登录状态”这个功能的话, 可以设定token失效期比如是7天, 然后用户每天登录的时候刷一次token。 这样除非用户一周内都没登录, 才会请求重新登录。

  • 我对互联网安全的认知是真的有限, 经常看文档, 一句话学到三四个新的词。 还是要多学习一个啊。 所谓苟日新,日日新,又日新是也。