Json Web Token 个人见解

jwt(Json Web token) 是一种用于不同组织之间交换数据的格式。既然名称中包含了Json,显而易见,其数据结构是以Json为基础进行搭建的。数据中包含了三个部分,headerpayload以及token。其中token可以使用私钥(HMAC算法),也可以基于公私钥的形式,通过对header及payload进行计算生成,从而达到校验header及payload数据合法性的作用。

使用场景:

  • 跨域认证。单点登录系统是最常见的jwt使用场景。用户在登录后,系统返回jwt的信息。后续的所有请求都会带上jwt的信息,从而认证该用户的信息。由于数据的请求可以通过header、cookies、参数等方式,使得跨域访问变得十分简单。
  • 跨域数据分享。通过使用公私钥的方法,客户端可以使用公钥对签发的数据进行校验,从而保证数据不被篡改。

结构

​ jwt包含了三个部分

  • header
  • payload
  • signature

从结构上来看,三个部分都为base64-URL编码后,使用.拼接后的数据:

​ eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.

​ eyJpc3MiOiJzdW1tZXJAdGVuY2VudCIsImFkbWluIjoiRmFsc2UiLCJleHAiOjE1MzkwNTMxODV9.

​ Tc8VyoGFihW_CBXnCIX6eHzbLo3WEQH-Sy65ohSWfqM

header

​ header包含了typalg两个部分:

{
  "alg": "HS256",  // 计算的方法
  "typ": "JWT"     // 都为JTW
}

payload

payload则包含了本次声明的数据。数据分为几个类型

  • jwt协议中定义的声明
    • iss 签发人
    • sub 主题
    • aud 受众
    • exp 过期时间
    • nbf 生效时间
    • jti jwt id
  • 通用的数据
  • 私有的数据: 用户自己定义的数据

一个payload的样例:

{
    "sub": "userinfo",
    "name": "testuser",
    "admin": false
}

signature

signature是对headerpayload的数据进行签名。签名的算法可以使用HMAC RSA256,也可以使用RSA256.前者需要所有的使用者都拥有加密的secret,后者的使用者则需要RSA的public key用于数据的解密。

signature的算法通常如下:

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

使用

从上面的定义来看,jwt本身是十分简单的。而且各种语言的JSON Parser都很全,所以相应的库也十分全面,基本常见的语言都是支持的。而且一种语言都有非常多的轮子,具体可以参考

这里就简单的以python作为样例,使用的是pyjwt,文档请参考

HMAC

import jwt
key = 'secret'
encoded = jwt.encode({'sub': '123456', 'user': 'testuser'}, key, algorithm='HS256')
decoded = jwt.decode(encoded, key, algorithms='HS256')

RSA

RSA算法的用法和HMAC类似

import jwt
encoded = jwt.encode({'sub': 123456, 'user': 'testuser'}, pri, algorithm='RS256')
decoded = jwt.decode(encoded, pub)

交互

How does a JSON Web Token work

jwt适用的场景是跨域的数据认证。通常的使用流程如下:

  1. client需要访问服务资源,首先请求认证服务器,通过相应的参数,获取合法的jwt token
  2. client在后续所有的访问中,都在请求包带上jwt token
  3. 资源的服务器校验该jwttoken是否合法。由于jwt的特性,校验可以在服务器本地完成,而不需要去请求远端的认证服务器。

请求时,带参数的方式有多种:

  1. cookies

    如果认证服务器与资源服务器是同域的,则可以把jwt token放在cookies进行携带。

  2. header

    对于跨域的情况,则可以在请求的header中添加Authorization: bearer <token>字段的方式来传递。由于是在header中添加数据,所以没有跨域的cookies无法携带的问题。

  3. params

    还有就是在请求的参数中增加token字段。比如Get方法中的url&token=xxx的形式,或者是Post中的请求参数

tips

使用claim校验

jwt官方定义了几种常用的claim,用于对数据合法性进行校验.常用的有:

  • exp: token的过期时间。

    服务端或者客户端进行decode时,可以自动捕获超时错误。

    jwt.encode({'exp': datetime.utcnow()}, 'secret')
    try:
        jwt.decode('JWT_STRING', 'secret', algorithms=['HS256'])
    except jwt.ExpiredSignatureError:
        # Signature has expired
    
  • nbf: token的启用时间

  • iss: token的签发者

  • aud: token的接受者

stateful & unstateful

stateful和unstateful是由jwt中数据存储的内容决定的. 如果jwt中的数据包含了所需要的全部数据, 每个client在使用数据时, 不需要再到某个服务中进行合法性校验, 则这个jwt是unstateful的, 反之, 则是stateful的.

举个例子:

{
    "uid": 123456,
    "exp": 1539148957,
    "group": "admin",
    "company": "1"
}

上面这个jwt包含了uid, group, company字段. 这些数据已经足够处理后续的所有请求了. 因此, client在执行的时候, 不需要再请求一次服务器, 获取剩余的数据. 这种jwt, 可以称之为 unstateful的.

再看下面这个:

{
    "uid": "sess-1234-412-x12",
    "exp": 1539148957
}

这个jwt中仅仅包含了一个uid信息, 所有的数据都没有. 在使用时, 还需要再请求一个服务获取相应的数据, 这种jwt就是stateful的.

当然, stateful的jwt, 也可以包含所有的数据.

{
    "uid": 123456,
    "exp": 1539148957,
    "group": "admin",
    "company": "1",
    "tid": "123-xx-xx"
}

在使用该jwt之前, 需要首先校验该tid是否还是合法. 一般会在一个服务器中维护一个tid的黑名单. 如果该tid属于黑名单中, 则强制废除该jwt.

安全问题

虽然token看起来是一段加密后的数据, 而且还用了加密算法, 但实际上并不是加密的. 回顾下token的样子,

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.

eyJzdWIiOjEyMzQ1NiwidXNlciI6InRlc3R1c2VyIn0.

NAHaQSXelvub7_y3XSXpofBQDuzBrGGxeJ4SAQPkYRE

token分成了三段:

  • header
  • payload
  • token

其中, header\payload都是仅仅用base64-URL encode后的结果. 也就是说,谁都可以做decode获取数据. 所以, jwt中一定不能包含涉密的数据,尤其是用户密码等敏感信息

性能问题

这里的性能问题, 指的是该结构带来的请求数据变多的问题. 在jwt的使用场景中, 所有的请求都需要完整带上jwt的数据. 由于payload这部分的数据仅仅是base64后的数据, 并没有做任何处理. 所以, 如果在payload中增加过多的数据, 就会导致jwt的结构变大, 从而导致请求的效率降低.

替代session

jwt的竞争对手并不是传统的session, 而是其他的跨域认证方案, 例如SAML以及SWT. 但是, 也有很多人使用jwt作为session的替代品进行使用. 选择jwt的原因大多数如下:

  • 平行扩容

    使用session的服务在用了jwt后, 完全可以在本地对jwt发过来的数据进行校验, 从而不需要传统的session记录. 因此, 当服务快速平行扩容时, 也不会因为session记录找不到而引起问题.

  • 免去session服务器

    同样的, 因为jwt已经记录了用户相关的信息, 也就不需要再去session获取一次用户的数据. 从而避免session服务器成为卡点.

当然, 这两点优势也饱受质疑.

首先, 现在session大多都直接存放在redis, memcache等缓存中, 已经没有什么人使用本地的文件存储了. 此外, 也可以通过负载均衡来保证访问都单用户请求都落在单一服务器上.

而对于免去session服务器, 则要看如何定义jwt中的数据. 前面说过, jwt可以是unstateful或者是stateful的. 对于unstateful的jwt, 当登录服务器签发了之后, 该jwt只要在exp之前都长期有效. 所以服务端是无法知道当前有多少用户在线. 这对于某些应用是不合适的. 而且, 废除jwt也成为了件难事. 如果需要废除已经签发, 但仍在有效期的jwt, 就需要添加一个黑名单, 那就变成了stateful的jwt, 而且也需要一个集中化的服务.

结论

jwt在2015年就已经成为RFC标准, 其token生成的设计, 很好的解决了不同组织之间相互数据信任的问题, 因而在单点认证方面得到了大规模的应用.

在单体服务中, jwt也被很多人用来作为session的替代品进行使用, 也引来了很多的讨论, 甚至是互喷. 整体上来说, 经过设计, 对于某些场景下, 由于签发的数据天然就带了可信任的token, 所以不需要再进行远端校验, 确实是能提高系统整体的吞吐率.

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

推荐阅读更多精彩内容

  • JWT 介绍 (https://jwt.io/) JSON Web Token(JWT)是一个开放标准(RFC 7...
    匆匆岁月阅读 5,483评论 1 41
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,106评论 18 139
  • 作者:阮一峰www.ruanyifeng.com/blog/2018/07/json_web_token-tuto...
    grain先森阅读 5,795评论 0 21
  • 文章转自:http://www.ruanyifeng.com/blog/2018/07/json_web_toke...
    daos阅读 800评论 0 3
  • 1. 微服务架构介绍 1.1 什么是微服务架构? 形像一点来说,微服务架构就像搭积木,每个微服务都是一个零件,并使...
    静修佛缘阅读 6,548评论 0 39