JWT Token的结构

JSON Web Token包含用点(.)分隔的三部分:

因此,一个JWT的形式是:
xxxxx.yyyyy.zzzzz


Header

Header通常包含两部分:

下面是一个例子:

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

使用Base64Url对Header进行编码,形成JWT的第一部分。


Payload

JWT的第二部分是payload,它包含声明。声明是关于实体(实体通常是用户)和可选的元数据的一系列语句。有三种类型的声明:预留的、公有的、私有的。

下面是一个例子:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

使用Base64Url对Payload进行编码,形成JWT的第二部分。


Signature

签名部分是使用编码后的header编码后的payload密钥以及header中指定的算法生成的。
比如,算法是HMAC SHA256,那么签名的计算方式是:

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

签名用于核实JWT的发送者,并确保消息没有被篡改。


合并起来

JWT包含三个用点分隔的Base64字符串。
下面是一个JWT的例子:

encoded-jwt.png

使用示例(Python)

思路是:将公钥给客户端,客户端使用公钥把数据加密发送给服务器端,服务器端根据信息的来源,使用对应的私钥进行解密。
需要安装的模块:
sudo easy_install pycrypto
sudo easy_install python_jwt

代码如下:

#coding: utf8

import datetime

import jwt
import Crypto.PublicKey.RSA as RSA

def gen_rsa_keys(bits):
    #随机地生成一个RSA key
    key = RSA.generate(bits)
    #返回编码后的私钥(str)
    priv_pem = key.exportKey()
    #返回编码后的公钥(str)
    pub_pem = key.publickey().exportKey()
    return priv_pem, pub_pem

def gen_rsa(bits=2048):
    priv_pem, pub_pem = gen_rsa_keys(bits)
    #导入RSA密钥(公钥或私钥),编码成标准形式
    return RSA.importKey(priv_pem), RSA.importKey(pub_pem)

priv_key, pub_key = gen_rsa(1024)
payload = {'foo': 'bar', 'wup': 90}

def client_side():
    return jwt.generate_jwt(payload, priv_key, 'RS256',
                datetime.timedelta(minutes=5))

def server_side(token):
    return jwt.verify_jwt(token, pub_key, ['RS256'])

if __name__ == "__main__":
    token = client_side()
    print token
    header, claims = server_side(token)
    print header
    print claims

输出:

eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9.eyJ3dXAiOiA5MCwgImp0aSI6ICJ5c090a2hEamhVaFZJTWtBMTQzdG13PT0iLCAiZXhwIjogMTQ1NDQ5NjU5NywgImlhdCI6IDE0NTQ0OTYyOTcsICJmb28iOiAiYmFyIiwgIm5iZiI6IDE0NTQ0OTYyOTd9.m_iHtfNz1wXzcBDMBMexPcgqKVQeJv6ngL3hagMHPnNPhq7kaBbaG0D0pYHfF6AZmItc3842dRjkJs4YwOV8jepdfbKjDBcUkcIXiQTw2ccAY69L2NDjEV-IHKAPGMulFwBykKNr0Ibdu185vWW8Wy6Hy15mskeTuwJ_fIrNZrM
{u'alg': u'RS256', u'typ': u'JWT'}
{u'wup': 90, u'jti': u'ysOtkhDjhUhVIMkA143tmw==', u'exp': 1454496597, u'iat': 1454496297, u'foo': u'bar', u'nbf': 1454496297}

JTI和replay attack

重放攻击(Replay Attacks)又称重播攻击、回放攻击或新鲜性攻击(Freshness Attacks),是指攻击者发送一个目的主机已接收过的包,来达到欺骗系统的目的,主要用于身份认证过程,破坏认证的正确性。
jti是被放到JWT中的唯一的ID,可以防止重放攻击。


参考文档