如何在 Spring 安全性中动态指定 OAuth2 资源详细信息?



我正在创建一个与Shopify的API集成的应用程序,该应用程序使用OAuth2进行身份验证和授权。 使用Spring Security OAuth2的教程和Shopify的教程,我已经能够与单个商店进行集成。 YAML 配置如下所示:

shopify:
shop: myshop
scopes: read_customers,read_orders
security:
oauth2:
client:
clientId: myclientid
clientSecret: mysecret
tokenName: access_token
authenticationScheme: query
clientAuthenticationScheme: form
accessTokenUri: https://${shopify.shop}.myshopify.com/admin/oauth/access_token
userAuthorizationUri: https://${shopify.shop}.myshopify.com/admin/oauth/authorize?scope=${shopify.scopes}&grant_options[]=
pre-established-redirect-uri: https://myapp/login
registered-redirect-uri: https://myapp/login
use-current-uri: false
resource:
userInfoUri: https://${shopify.shop}.myshopify.com/admin/shop.json

但是,此静态配置不适用于在 Shopify 应用商店中发布的应用,因为重定向、访问令牌、用户信息和用户授权 URI 取决于商店名称。 有一些使用多个提供程序的示例,但它们仍然是静态的。

为了使这些 URI 是动态的,我提出了一些可能的选项:

  1. 使用/login路径中的参数来标识商店,然后创建一个过滤器,将商店名称添加到在其他所有内容之前运行的ThreadLocal,然后通过 Spring 代理的工厂 bean 动态创建 OAuth2 过滤器所需的AuthorizationCodeResourceDetails

  2. 使用一种"元过滤器",动态地重新创建每个请求的OAuth2ClientAuthenticationProcessingFilter以及它所需的所有资源。

  3. 重写OAuth2ClientAuthenticationProcessingFilter,以便它可以处理重新创建获取访问令牌所需的RestTemplate

所有这些选择似乎都非常困难。 在 Spring Security OAuth2 中处理动态生成的访问令牌和用户信息的 URI 的好方法是什么?

另外,由于我一般是OAuth2的新手,我是否需要在我的Spring配置中启用资源服务器以使用访问令牌保护我的应用程序?

有点晚了,但我确实通过覆盖 Oauth2ProtectedResource 的 getter 返回了 oauth 资源的动态 url

@Bean(name = "googleOauthResource")
public BaseOAuth2ProtectedResourceDetails getGoogleOauthResource() {
final AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails() {
@Override
public String getPreEstablishedRedirectUri() {
final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes instanceof ServletRequestAttributes) {
final HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
return request.getRequestURL() + "?" + request.getQueryString() + "&addStuff";
}
return super.getPreEstablishedRedirectUri();
}
};
details.setId("google-oauth-client");
details.setClientId("xxxxxxxxxxx");
details.setClientSecret("xxxxxxxx");
details.setAccessTokenUri("https://www.googleapis.com/oauth2/v4/token");
details.setUserAuthorizationUri("https://accounts.google.com/o/oauth2/v2/auth");
details.setTokenName("authorization_code");
details.setScope(Arrays.asList("https://mail.google.com/,https://www.googleapis.com/auth/gmail.modify"));
details.setPreEstablishedRedirectUri("http://localhost:8080/xxx-api-web/v2/gmail"); //TODO
details.setUseCurrentUri(false);
details.setAuthenticationScheme(AuthenticationScheme.query);
details.setClientAuthenticationScheme(AuthenticationScheme.form);
details.setGrantType("authorization_code");
return details;
}

我遇到了和你一样的问题,我倾向于你使用ThreadLocal存储的第一个理论。 以下是我可能会如何进行我的解决方案:

通过覆盖 OAuth2ClientAuthenticationProcessingFilter 中的方法,在 LocalThread 存储中设置 ServletRequest 的值:

  • 尝试身份验证
  • 成功身份验证
  • 不成功身份验证
  • 需要身份验证

然后通过覆盖以下方法转换 OAuth2RestTemplate 中的 URI:

  • 创建请求
  • 执行
  • 追加查询参数

我可能不得不为具有注入@Service的 RestTemplate 制作自己的@Bean,该模板将查找动态 Shopify 域。

如果可行,我会发布我的解决方案。

最新更新