Spring security oauth2 - 从 OAuth2 主体获取自定义数据
Posted
技术标签:
【中文标题】Spring security oauth2 - 从 OAuth2 主体获取自定义数据【英文标题】:Spring security oauth2 - getting custom data from OAuth2 principal 【发布时间】:2013-04-17 00:00:42 【问题描述】:我有一个使用 Spring 安全性并具有用户(用户名和密码)和标准表单身份验证的站点。我允许用户生成与他们的帐户相关联的客户端 ID 和客户端密码,以便与 OAuth2 安全的 rest API 一起使用。
我为 API 使用单独的客户端 ID 和客户端密码,而不是用户名和密码,因此用户可以在不破坏 API 凭据、设置特定范围、禁用 API 访问等的情况下更改密码等。
我使用 spring-security-oauth2(提供者)来保护其余的 API,并且我允许客户端凭据流。我已经为 api 设置了客户端身份验证,以便检查客户端 ID 和密码。
从一个单独的应用程序中,我使用客户端 ID 和客户端密码来检索访问令牌并开始将其与 api 一起使用。在大多数情况下,我使用简单的 @PreAuthorize 表达式,通常基于客户端角色和范围,并且这些表达式似乎可以正常工作。
以上一切似乎都可以正常工作
但是...我现在有一些 API 端点,但是我需要根据来自底层用户的一些详细信息来实现一些更复杂的规则 - 在本例中是生成客户端 ID 和密码的用户。
作为一个简单的例子,考虑一个消息传递应用程序,其中我有一个端点,允许用户发布可以变化的特定类型的新“消息”。我有每个用户和每种类型的允许收件人表,我想检查已发布消息的收件人是否与该类型的允许收件人匹配。 (用户允许的收件人数据通常不大,并且很少更改,因此我很乐意在生成访问令牌时存储它的副本)
我在这些端点获得了主体,我看到它是 OAuth2Authentication 的一个实例,其中包含:
userAuthentication - null - 这对于客户端凭据流来说似乎是可以预期的。 clientAuthentication 已填充,authorizationParameters 包含授权类型和 client_id我想我可以使用 clientAuthentication.authorizationParameters 中的客户端 ID 来查找用户和我需要的详细信息,但这将是每个 api 调用的一些查询,这似乎没有意义。
我猜想 Spring OAuth2 库中有一个不错的地方/方式,在授予访问令牌的同时,我可以添加一些额外的细节,以便稍后我可以从 OAuth2Authentication(主体)对象(或扩展它的东西? )
或者是否有更好的方法完全解决此类问题?
谢谢!
【问题讨论】:
你看过 JWT(JSON 网络令牌)吗?它几乎是一个包含所有有用信息的令牌。 【参考方案1】:您可以覆盖令牌创建类,以便令牌本身包含用户名。 (可能使用 client_secret 加密)。 这样,您可以从令牌本身获取与令牌相关的用户,而无需额外的数据库访问。 你应该覆盖
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
使用您自己的课程,或使用TokenEnhancer
【讨论】:
谢谢,最初听起来很有希望。我会检查更多,并在第二天进行一些测试。我还没有找到一篇文章/帖子/示例,所以如果你知道,请告诉我:) 嗨,我检查了一下,似乎 TokenEnhancer 有助于“增强”访问令牌响应和/或添加一些额外的信息。虽然那不是我想要的。应该不需要将额外的数据发送回客户端。虽然我理解您尝试将用户名填充到令牌中的想法(我通常不需要它),但在我看来,必须有更好的方法使令牌等保持不变并且只发生在服务器端。 您可以在使用ClientDetails.addAdditionalInformation
注册每个客户时将所需的信息添加到您的客户详细信息中,然后您可以使用您获得的clientId
检索此信息。 (这可能需要每个请求一个查询,这似乎是合理的)
好点。是的,检索很遗憾,我想避免。看起来扩展点/字段还没有。我有自己的暗示。 TokenStore,ClientDetail,ClientDetailService,但似乎我必须修改太多才能创建完整的链。【参考方案2】:
在我看来,正确的方法是使用 oauth2 “密码”流程而不是客户端凭据。您可以创建一个通用的客户端 ID 和客户端密码,并将它们提供给您的所有用户。每个用户都可以使用这些客户详细信息以及他自己的用户名和密码来请求他自己的令牌。 这样,每个令牌都将连接到一个 UserDetails 对象,这将解决您的问题。 你可以在这里看到这是如何完成的:https://labs.hybris.com/2012/06/18/trying-out-oauth2-via-curl/
【讨论】:
感谢您的想法,但使用客户端凭据的目的是使 API 通常独立于用户。只有在少数情况下(少数)我有一些更复杂的规则。我已经更新了问题,以说明客户端凭据的原因。 此处的链接已损坏。你能带来这个特定答案的相关sn-p吗? 链接又被破坏了。【参考方案3】:为什么您不使用可以在客户端详细信息中定义的范围,然后使用 ScopeVoter 验证此令牌是否具有访问此资源的适当范围。
请查看我的演示了解更多详情
https://github.com/bassemZohdy/Spring_REST_OAuth_Demo
更新 1: 我没有回答您的问题“从 OAuth2 主体获取自定义数据”的第 2 部分,您可以在授权服务器上添加休息服务,使用 OAuth 令牌访问该服务,为您提供有关此令牌用户的所需信息,因此您不必关心“OAuth2 主体”,您也将授权服务器作为资源服务器处理。
【讨论】:
Thx,我已经在使用一些简单的范围,但避免了该解决方案,因为我担心范围的数量会爆炸性地达到我想要的规则。我会用一个例子来更新这个问题。 在另一个解决方案中,我使用每组资源的范围,我认为范围的数量没有限制,您也可以将范围与角色混合使用。 谢谢,是的,我已经使用了这么一点。仅就我提到的情况而言,从用户那里制定范围然后对其进行处理以解释它们可能会令人费解:-)我希望有更好的方法。以上是关于Spring security oauth2 - 从 OAuth2 主体获取自定义数据的主要内容,如果未能解决你的问题,请参考以下文章
Spring-Security OAuth2 设置 - 无法找到 oauth2 命名空间处理程序
Spring Security OAuth2 v5:NoSuchBeanDefinitionException:'org.springframework.security.oauth2.jwt.Jwt
如何使用spring-security,oauth2调整实体的正确登录?