OAuth 2.0实战课
王新栋
京东资深架构师
立即订阅
2496 人已学习
课程目录
已完结 17 讲
0/2登录后,你可以任选2讲全文学习。
开篇词 (1讲)
开篇词 | 为什么要学OAuth 2.0?
免费
基础篇 (6讲)
01 | OAuth 2.0是要通过什么方式解决什么问题?
02 | 授权码许可类型中,为什么一定要有授权码?
03 | 授权服务:授权码和访问令牌的颁发流程是怎样的?
04 | 在OAuth 2.0中,如何使用JWT结构化令牌?
05 | 如何安全、快速地接入OAuth 2.0?
06 | 除了授权码许可类型,OAuth 2.0还支持什么授权流程?
进阶篇 (8讲)
07 | 如何在移动App中使用OAuth 2.0?
08 | 实践OAuth 2.0时,使用不当可能会导致哪些安全漏洞?
09 | 实战:利用OAuth 2.0实现一个OpenID Connect用户身份认证协议
10 | 串讲:OAuth 2.0的工作流程与安全问题
11 | 实战案例:使用Spring Security搭建一套基于JWT的OAuth 2.0架构
12 | 架构案例:基于OAuth 2.0/JWT的微服务参考架构
13 | 各大开放平台是如何使用OAuth 2.0的?
14 | 查漏补缺:OAuth 2.0 常见问题答疑
结束语 (2讲)
期末测试 | 一套习题,测试你的掌握程度
结束语 | 把学习当成一种习惯
OAuth 2.0实战课
15
15
1.0x
00:00/00:00
登录|注册

04 | 在OAuth 2.0中,如何使用JWT结构化令牌?

王新栋 2020-07-07
你好,我是王新栋。
在上一讲,我们讲到了授权服务的核心就是颁发访问令牌,而 OAuth 2.0 规范并没有约束访问令牌内容的生成规则,只要符合唯一性、不连续性、不可猜性就够了。这就意味着,我们可以灵活选择令牌的形式,既可以是没有内部结构且不包含任何信息含义的随机字符串,也可以是具有内部结构且包含有信息含义的字符串。
随机字符串这样的方式我就不再介绍了,之前课程中我们生成令牌的方式都是默认一个随机字符串。而在结构化令牌这方面,目前用得最多的就是 JWT 令牌了。
接下来,我就要和你详细讲讲,JWT 是什么、原理是怎样的、优势是什么,以及怎么使用,同时我还会讲到令牌生命周期的问题。

JWT 结构化令牌

关于什么是 JWT,官方定义是这样描述的:
JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为 JSON 对象在各方之间安全地传输信息。
这个定义是不是很费解?我们简单理解下,JWT 就是用一种结构化封装的方式来生成 token 的技术。结构化后的 token 可以被赋予非常丰富的含义,这也是它与原先毫无意义的、随机的字符串形式 token 的最大区别。
结构化之后,令牌本身就可以被“塞进”一些有用的信息,比如小明为小兔软件进行了授权的信息、授权的范围信息等。或者,你可以形象地将其理解为这是一种“自编码”的能力,而这些恰恰是无结构化令牌所不具备的。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《OAuth 2.0实战课》,如需阅读全部文章,
请订阅文章所属专栏新⼈⾸单¥9.9
立即订阅
登录 后留言

精选留言(26)

  • Neo
    老师,您好,有2个疑问:
    1. 在jwt.io网站上验证的时候,如果不输入密钥,返回invalid Signature, 但是header和payload信息依然可以正确显示。我的理解是,在生成header和payload部分的时候,是通过base64编码,没有进行加密处理。最后的签名是保证整个body在传输的过程中没有被篡改。那么是不是意味着使用JWT方式,信息的主体还是依然能被未授信的第三方获取到?
    2. 您提到JWT的一个优势是资源服务器不需要依赖数据库存储相关的信息,从而易于横向扩容。但是密钥部分还是躲不过需要查询的,可能依然需要存储。另外,如果采取一个用户用一个密钥的方式,资源服务器如何知道某个JWT token是给哪个用户使用的?(用户信息包含在header or payload中?)
    谢谢

    作者回复: 1、JWT肯定要加密传输,这点我们文中强调了,不做加密的结果就是你说的,加密用对称和非对称都可以,看实际需要,追求性能就是对称,可通过管理秘钥来对冲掉对称带来的相比非对称的弱化的那部分安全。

    2、是的,用生成秘钥的方法,这是管理我们扔出去的JWT TOKEN的方式之一,如果只靠有效期当然也可以,但如果追求更进一步管理的话就需要做点额外的消耗。如果通过秘钥来管理,就需要一个秘钥管理系统,另外JWT肯定是要加密处理,而且加解密的重点不在于加解密算法,而在于秘钥管理,需要我们要把秘钥生成在独立于授权系统之外的秘钥管理系统里面,存储关系就是app_id+用户=秘钥,这里的用户就是TOKEN换取出来的。

    2020-07-07
    1
    7
  • 刘丹
    我对JWT的理解是:JWT本身只对payload进行了签名,并没有做加密(base64编码不算加密)。文中多次提到加密,我比较疑惑,是我的理解错了吗?

    作者回复: 你理解是对的,签名是签名,加密是加密。

    通过阅读官网上的下面这段话,可以帮助理解,在官网上有这么一段话:
    “Signature
    To create the signature part you have to take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that.

    For example if you want to use the HMAC SHA256 algorithm, the signature will be created in the following way:”

    意思是,用SHA256加密算法进行签名。

    像我们熟知的MD5,SHA-0,SHA-1都是签名的算法,但也都都是计算机密码学中的最经典的加密算法,由于对MD5、SHA-0和SHA-1出现过成功的碰撞破解,现在已升级更新成SHA-2、SHA-3,而SHA256属于SHA-2。

    签名实际上是一个加密的过程。在我们给的例子中使用了JJWT这个三方工具库,它的内部帮我们实现了签名和加密的工作以及包括验证签名的工作。

    我们例子中给的是HS256算法,因为对称比非对称效率高些,但同时我们又做到了用户粒度的秘钥控制,来抵消对称不如非对称的那部分安全性,所以我们采用了对称的算法。

    2020-07-10
    2
  • 哈德韦
    如果需要从服务器端直接暴力将某些用户“踢出下线”,是不是就不能使用 JWT 令牌?除非在另外的密钥管理系统里,将这些用户的密钥强行改掉?

    作者回复: 可以使用JWT令牌,为了解决“覆水难收”的问题,需要额外的成本来处理,就是管理那个秘钥。就类似你说的“强行改掉”,这样当JWT请求到平台的服务端的时候就验证不通过了,也就是类似你说的“踢出下线”。

    2020-07-13
    1
  • 业余草
    JWT 令牌如何刷新,有没有好的方案给我们讲一讲?

    作者回复: 刷新令牌的使用方法,跟是否JWT令牌和普通的令牌没有区别。

    2020-07-09
    2
    1
  • inrtyx
    密钥肯定要定期更换吧?如果是的话,密钥的管理是个问题,密钥换的话,客户端和服务端都要换的吧,关于密钥管理,老师有没有什么好的实践吗?
    2020-07-07
    1
  • Geek_7c4953
    如果JWT需要加密,那解密的秘钥要存储在哪呢?如果是web场景,在JS中存储秘钥跟明文没有差别啊。还是说JWT只能用于服务器之间的授权访问?

    作者回复: 第三方软件永远不会对JWT格式的访问令牌进行解密的。

    2020-08-10
  • Geek_7932
    老师,感觉JWT在文章中的讲解在加密、解密这一块稍微有点模糊,不易理解
    JWT在这里的作用主要是将用户授权信息保存在结构体中,生成和内容校验都是在授权服务和受保护资源这一方
    对于第三方应用来说,JWT和UUID的token都是一样的,就是个授权字符串;而对于授权服务这方来说,是不太一样的,JWT上存用户授权信息,而UUID则是在数据库存授权信息
    对于JWT是否使用对称和非对称加密,密钥/(公钥、私钥)都只是授权服务/受保护资源这一方用到了,选择哪种加密方式其实在这差别不大,密钥/(公钥、私钥)都不会公开出去,而且对称加密还有速度更快的优势,或许对称加密在这更加合适

    作者回复: 你的理解是对的

    2020-08-10
  • 哈德韦
    文中说JWT的加密算法,既可以是对称加密,也可以是非对称加密。这里的对称加密是不是不包括 base64?感觉只用base64的话,和不加密没有区别(贴到https://jwt.io/就可以看到明文)。

    作者回复: base64只是编码

    2020-08-02
  • 李顺翔
    把用户密码当做秘钥不合适吧,如果用户修改密码,所有的授权都会失效

    作者回复: 用户修改密码,这个动作本身在安全背后是一件很严密的事情,对授权系统来讲,它接收到的事件,就是密码修改了,它的反应一定要让授权失效,因为授权系统不知道谁修改了密码。

    2020-07-27
  • 哈德韦
    请问老师,既然不能让JWT不可控,就要用户粒度的密钥管理,在我的理解,就是至少维护一个用户和密钥的键值对,那这和 Session 管理是不是本质上一样?

    作者回复: 本质还不一样,session管理的本质是会话管理,用户粒度的秘钥管理并不会涉及到【会话】层面,归根结底这里讲到的JWT令牌的本质是起到访问令牌的作用。

    2020-07-22
  • Yuhui
    请教老师,图4令牌生命周期序列图里最后两项“撤回访问令牌”和“撤回刷新令牌”是否应该调换一下顺序?

    作者回复: 从理解上,是应该先撤回刷新,再撤回访问,但实际上 程序在执行的时候,是放在一个事务中,要么同时成功,要么同时失败。

    2020-07-22
  • lign
    老师,如果对JWT加密,资源服务器收到加密后的JWT串,需要解密时,JWT里面的内容,怎么获取解密密码?需要到独立密钥管理系统请求解密密码? 如果是这样,JWT协议本身是不是相当于信息在裸奔?如果不额外增加加密过程的话

    作者回复: 如果JWT不额外加密就相当于裸奔。当资源服务器收到加密之后的JWT令牌,会要到秘钥系统请求秘钥,但这个并不会有任何性能上的问题,一般都是直接读取redis存储。

    2020-07-17
  • piboye
    jwt如果每个用户一个密钥,就还需要访问数据库,这种方式和无结构的token优化没那么明显,只是省了token的存储。

    作者回复: 存储节省不明显是在用户量少的情况下。秘钥管理系统是JWT和OAuth 2.0 之外的成本,安全问题的防护是一个成本问题,如果是低等级防护,当然可以直接使用JWT的令牌短时过期。

    2020-07-14
  • 蓝魔丶
    老师,我看了评论说jwt这种token不传递前端进行交互,如果是之前的授权码方式觉得可以不传,如果是用户名密码方式呢?不是还是要传递前端嘛?而且给我的感觉jwt这种token会随着存入的json数据越多越长,基本的json数据就感觉很长了

    作者回复: JWT的签名不会变长,如果再为其加密会随着数据内容增多而变长,但我们是不建议把大量的数据放入这样的结构体中的。

    2020-07-13
  • 蓝魔丶
    老师,jwt中signature已经在签名的时候用到了一个secret,这样已经能保证只有知道secret的第三个方才能验证jwt合法性,为什么还要加密,为了防止解密出head和payload?

    作者回复: 是的,为了防止解密出payload。在将JWT用作【访问令牌】的时候,令牌的内容第三方应用也是不能被允许知道的,对于第三方应用来讲【访问令牌】对它不透明。

    不过当我们讲到09的时候,通过OAuth 2.0 来实现一个用户身份认证的时候会用到【ID令牌】,这个【ID令牌】允许被第三方软件解析,因为这种情况需要一个用户标识。

    2020-07-13
    1
  • Max
    老师您好,如果传输层已经是加密的(TLS),JWT就不用加密了吧(用签名来保证数据完整性应该就够了)

    作者回复: 不可以。无论什么形式的【访问令牌】都需要保证对【第三方软件】不透明。

    2020-07-11
    1
  • 一步
    利用 JWT 生成 base64UrlEncode(header).base64UrlEncode(payload).HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),11111111111) 这样的一个字符串后,是不是在网络中传输还要把这一串在加密一下?, 要不然就可以直接获取 payload 的信息了, 这里面的 11111111111 就相当于密钥了可以控制到用户级别?
    2020-07-09
    1
  • 约书亚
    请问一个用户一个密钥这种方案用的多么。
    我感觉无论怎么设计,受保护资源都要存储额外存储一些信息才行,这样JWT的优势就没了。
    既然这样我们为什么不用一个随机生成的token代替JWT,让受保护资源通过调用授权服务的接口来验证token以及权限呢?
    确实这JWT方案可以减少对授权服务的请求,但还多了同步密钥信息的功能,如果有多个资源服务需要验证token,那是不是密钥信息要冗余多处,增加了泄漏的风险?

    作者回复: 如果要做到细粒度的安全控制,肯定是要缩小到一个用户一个秘钥的粒度。

    秘钥信息的管理涉及到额外的一套秘钥管理系统。

    2020-07-08
    1
  • 大秦皇朝
    JWT适合多组权限校验,非JWT(非结构化的)适合接口调用?不知道理解的对不对。
    2020-07-08
  • 赵嘚住
    老师,您好,还有个问题,既然说了减少和数据库的调用次数,那jwt的第三部分秘钥如果验证他的准确性?这个秘钥不也是要存储在数据库,当接受到token解密以后,通过信息在数据库中查出来对比以后才能验证通过,或者rpc以后验证?这样总还是要查询数据的,只是没有暴露密码而已,但很多问题还是没有解决?求老师解答

    作者回复: 减少数据库查询次数是相对于普通的token来说的,普通的token是一个无意义的随机的字符串,需要再次匹配数据库拿到更多的用户信息,比如哪个用户给哪个应用授权了。结构化JWT令牌自包含了这些信息,所以不需要额外的查询数据库。

    但是,我们需要对JWT令牌数据进行加密,这就引出另外一个加密的问题,在回答其他同学的时候也提到了这点,加密的重点是秘钥管理,这已经是超出了JWT的范围了,JWT设计的时候它关注的是结构化,所以对于加密这套系统的设计就需要额外的考虑。

    我们是一定要能够做到对扔出去的JWT令牌做到可控的,也就涉及到更细粒度的秘钥管理,这时,可以采用redis这样的分布式缓存或者本机缓存来解决查询秘钥更新的问题,用普通的mysql做持久化,更新的时候更新到redis或者本地缓存的数据。

    2020-07-08
收起评论
26
返回
顶部