我正在创建一个与Shopify的API集成的应用程序,该API使用OAuth2进行身份验证和授权。使用the tutorial for Spring Security OAuth2和the tutorial for 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 App Store中发布的应用,因为重定向,访问令牌,用户信息和用户授权URI取决于商店名称。 There are examples of using more than one provider,但它们仍然必须是静态的。
为了让这些URI变得动态,我想出了一些可能的选择:
使用/login
路径中的参数来标识商店,然后创建一个过滤器,将商店名称添加到先前运行的ThreadLocal
,然后动态创建{{通过Spring代理的工厂bean,OAuth2过滤器需要它。
使用一种“元过滤器”,可以为每个请求动态重新创建AuthorizationCodeResourceDetails
及其所需的所有资源。
覆盖OAuth2ClientAuthenticationProcessingFilter
,以便它可以处理重新创建获取访问令牌所需的OAuth2ClientAuthenticationProcessingFilter
。
所有这些选项似乎都很难。在Spring Security OAuth2中处理动态生成的URI以获取访问令牌和用户信息的好方法是什么?
此外,由于我一般不熟悉OAuth2,我是否需要在Spring配置中启用资源服务器以使用访问令牌保护我的应用程序?
答案 0 :(得分:2)
有点晚但我通过覆盖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;
}
答案 1 :(得分:1)
我遇到了同样的问题,而且我倾向于使用ThreadLocal存储的第一个理论。以下是我可能会解决的问题:
通过覆盖OAuth2ClientAuthenticationProcessingFilter中的方法,在LocalThread存储中设置ServletRequest的值:
然后通过覆盖followign方法翻译OAuth2RestTemplate中的URI:
我可能不得不为RestTemplate创建自己的@Bean,它会注入@Service来查找动态Shopify域。
如果有效,我会发布我的解决方案。