JWT`Scope`声明压缩

2020-05-23 18:00:40

JWT通常用于无状态身份验证流。多亏了签名,服务器不需要任何其他东西来验证令牌的有效性。作用域声明(RFC8693第4.2节)包含与令牌相关联的作用域的空格分隔列表。服务器可以使用它来检查应用程序权限,尽管这一要求可能很快就会变得繁重。作用域越多,令牌就越大!但是jwt应该是紧凑的令牌格式…。

今天,我很自豪地向您介绍一个想法,将作用域列表压缩成一个位图,其中一位代表一个作用域。

这个想法很简单。我将每个作用域与字节序列中的一个位相关联,而不是包含与该令牌相关联的所有作用域的巨大字符串。每一位都告诉我们作用域是否与令牌关联(或不关联)。

0 1 1 0 1 0 0 1 1 1 0 1(.)Scope_a──┘│Scope_b─┘│Scope_c─┘┆(.)┆。

正如您已经知道的,字节数组不是JSON数据类型。但这没什么大不了的,我们可以用64进制对这些字节进行编码。

我不想覆盖当前的范围声明规范。即使从技术上讲它不会违反规范(因为我们仍然在里面存储一个字符串),这也不是一个好的实践,IMO。此外,在某些情况下,您可能希望同时拥有传统作用域声明和位图作用域声明。

任何资源提供程序都在记录其API中可用的作用域列表。它是在“人类可读的”文档(文本、HTML、PDF、…)中定义的。或者采用结构化规范(OAuth Authorization Server元数据、OpenID连接发现、OpenAPI、…)。。

对于结构化规范,我的建议是保持相同的有序列表,并使用每个作用域的索引作为位号。OAuth元数据中的SCOLES_SUPPORTED字段是一个JSON数组。元素的顺序被保留。但是,OpenAPI中的Scope字段是一个映射(JSON对象)。我们不应该依赖于钥匙的排序。OpenAPI规范很有希望允许扩展。这意味着我们可以定义一个x-scope-order关键字,该关键字将列出(JSON数组)具有保留顺序的作用域(就像在OAuth元数据中一样)。

假设您的API中有42个作用域(我以Facebook API为例)。在位图中存储它们将需要6个字节。由于采用Base64编码,我们必须做4*n/3(+四舍五入的乘数4)=8字节。为了公平起见,我在声明名称中添加了2个字节(前缀b_与作用域Claim相比),总共10个字节。作用域列表电子邮件名称的大小相等。

使用二元运算符测试字节序列不会消耗CPU。与字符串操作和比较相比,它的性能可能更好。

LSB vs MSB。目前我不知道最好的选择是什么。我想答案应该来自以下几个标准:

什么是最有效的/最好的?要用多种面向网络的语言(JS、Python、Ruby、Rust、SWIFT、…)进行测试。

您可能想要弃用某个作用域,但是您不能从列表中删除此作用域,否则它会移动后面所有其他作用域。

在这种情况下,你会松一点。但是如果您的令牌时间有限,您可以在一段弃用时间(长于最长令牌生存期)之后用另一个位作用域替换该位作用域。

有些人正在定义“动态”范围。例如:perts.{id}.read。我认为这不是一个好的做法。我对作用域的理解是授予对API功能的访问权限,而不是对资源本身的访问权限。换句话说,您应该只有一个允许应用程序读取宠物的作用域pet.read。您的资源(也称为内容)ACL不应该在作用域本身中。

有何不可?我还没有分析我们可以在哪里以及如何使用它,但是我猜在某些情况下它可能会很有用,但是我看不出在OAuth(令牌和授权)端点中使用它有什么大的好处。在每个API请求中发送JWT时,会准时调用这些端点。

你可能有问题,或者你只是想讨论一下。请在我的博客库中打开问题,或随时给我发电子邮件。