这是一篇关于 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 OPTIONAL
RFC2119还定义过啥叫OPTIONAL

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

那token会不会很大?

有可能会。

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

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

与其他鉴权方式的对比

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

JWTOAuthSessionHawk
易用性容易,就一个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。
    这样除非用户一周内都没登录,
    才会请求重新登录。

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