限制对单个资源的访问的 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."
我们利用第三方电子邮件服务提供商 (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."