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

Posted

技术标签:

【中文标题】如何在 Spring Security 中动态指定 OAuth2 资源详细信息?【英文标题】:How do I dynamically specify OAuth2 resource details in Spring Security? 【发布时间】:2017-10-05 06:40:57 【问题描述】:

我正在创建一个与 Shopify 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 应用商店中发布的应用,因为重定向、访问令牌、用户信息和用户授权 URI 取决于商店名称。 There are examples of using more than one provider,但它们仍然必须是静态的。

为了让这些 URI 成为动态的,我想出了几个可能的选项:

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

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

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

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

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

【问题讨论】:

嗨@Brad,我也有类似的问题。你想好怎么做了吗? 可悲的是,只是理论上。这将需要对图书馆的工作方式进行一些非常重大的改变; @EnableOAuthSso 注释给你的东西真的只对静态网站有用。您必须创建新类并将 bean 连接起来才能以不同的方式做事。 我也在寻找这个问题的答案。你有进步吗?我会看看我能不能把东西放在一起。 目前还没有。我一直在努力让 Spring Security 向我提供我需要的 Shopify 信息(例如商家名称)的委托人,所以我没有时间看这个。 【参考方案1】:

有点晚了,但我确实通过覆盖 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;

【讨论】:

【参考方案2】:

我遇到了与您相同的问题,并且我倾向于您使用 ThreadLocal 存储的第一个理论。以下是我可能会如何解决我的解决方案:

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

尝试身份验证 认证成功 身份验证失败 需要身份验证

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

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

我可能必须为 RestTemplate 创建自己的 @Bean,该模板具有注入的 @Service 将查找动态 Shopify 域。

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

【讨论】:

以上是关于如何在 Spring Security 中动态指定 OAuth2 资源详细信息?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring Security 中动态决定 <intercept-url> 访问属性值?

Spring Security:如果没有指定@PreAuthorize,如何默认拒绝请求

如何使用 Spring Security OAuth2 提供程序配置指定要保护的资源

如何使用 spring-social-security SocialAuthenticationFilter 指定 OAuth2 范围?

Spring Security 3.0:如何指定应用自定义过滤器的 URL?

在 Spring Security 3 中动态创建新角色和权限