限制对单个资源的访问的 Oauth2 令牌

Oauth2 token that restricts access to a single resource

我们利用第三方电子邮件服务提供商 (ESP) 向我们的客户发送电子邮件。其中一封电子邮件需要附加一个文件。为此,我们需要为 ESP 提供文件的 URL。 ESP 将下载文件并将其附加到电子邮件中。

我们现在正在研究一种解决方案来保护 URL 以限制未经授权下载的风险。 ESP 在向 URL 发出请求时无法验证自身,因此我们看到的唯一选择是让 URL 难以猜测并使其在有限的时间内有效。

我们想要完成此操作的方法是在 URL 的查询字符串中放置一个标记。托管文件的服务将验证令牌并授权访问。令牌需要及时过期,并且应该只允许访问特定文件。

我们已经有一个 IdentityServer 3 实现 运行 一个 oAuth2 安全令牌服务。我们的计划是让该服务生成令牌,这些令牌将放入文件下载的查询字符串中 URL。我们正在考虑创建自定义 oAuth2 授权类型以支持只允许访问特定资源的令牌。

这是一个使用自定义授权请求 oauth2 令牌端点的示例:

 POST /token HTTP/1.1
 Host: server.example.com
 Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
 Content-Type: application/x-www-form-urlencoded

 grant_type=custom_grant&scope=attachment.read&resource_id=xxxxx

STS 将 return 一个令牌,其中声明了该令牌将授予访问权限的资源 ID。

自定义授权类型的正确用例还是我们应该寻找不同的方法来实现它?

我认为你的建议很好,但我个人更喜欢使用基于密码签名的东西来处理这类事情。

JSON Web Token 是一种行之有效的方法,支持多种编程语言。本质上,你签署了一个 JSON 字典,包括一个过期时间。然后将它附加到 URL (例如作为查询参数)。收到入站请求时,您通过检查签名、过期时间和它表示适用的资源来验证令牌。

这种方法的优点是没有不必要的状态:您不必在任何地方存储令牌,而只需要一个签名密钥。

Python 中的一个示例展示了基本思想:

import time

import jwt

SIGNING_SECRET = 'use-a-good-secret-here'

token = jwt.encode({
    'resource_id': 'xxxxx',
    # JSON spec establishes "exp" as meaning expiration time
    'exp': time.time() + 1, # one second in the future for testing
}, SIGNING_SECRET, algorithm='HS256')

print(token)

def try_decoding(token):
    try:
        decoded = jwt.decode(token, SIGNING_SECRET, algorithms=['HS256'])
        print('Valid token for "{}"'.format(decoded['resource_id']))
    except jwt.exceptions.ExpiredSignatureError:
        print('The token has expired.')

try_decoding(token) # prints 'Valid token for "xxxxx"'
print('Sleeping until the token expires...')
time.sleep(2)
try_decoding(token) # prints "The token has expired."