2

我正在构建一个支持多个租户的 Spring Social 应用程序。应用程序根据 url 识别租户(例如,tenant1.example.com 和tenant2.example.com)。我想允许应用程序的用户使用 Facebook 或 Twitter 进行连接。我遇到的问题是每个租户都是一个独特的企业,并且将拥有自己独特的一组 Facebook 和 twitter 凭据。我认为我的 ConnectionFactoryRegistry 中不能有多个 Facebook ConnectionFactory 实例或多个 Twitter ConnectionFactory 实例。例如,这将不起作用:

ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();
registry.addConnectionFactory(new FacebookConnectionFactory("tenant1ClientId", "tenant1ClientSecret"));
registry.addConnectionFactory(new FacebookConnectionFactory("tenant2ClientId", "tenant2ClientSecret"));

以上将不起作用,因为根据 Spring Social 文档,定位器返回单个实例。

public interface ConnectionFactoryLocator {
   ConnectionFactory<?> getConnectionFactory(String providerId);
   <A> ConnectionFactory<A> getConnectionFactory(Class<A> apiType);

   Set<String> registeredProviderIds();
}   

我曾考虑在 preConnect() 步骤中创建一个 ConnectInterceptor 并将相关的租户凭据注入到提供的 ConnectionFactory 实例中,但我怀疑这在多线程 Web 应用程序中不起作用,因为 connectionFactory 实例是共享的。

因此,我的下一个想法是简单地为每个租户创建一个唯一的 ConnectionFactoryRegistry 实例。这样就解决了上面的问题。

但随后问题转移到了 ConnectController(Spring 的 OAuth 舞蹈控制器)。由于应用程序只能有一个控制器,而控制器只有一个注册表,我将如何根据租户指示控制器使用正确的注册表?

构建支持每个租户的唯一 ConnectionFactory 实例的多租户 Spring Social 应用程序的正确方法是什么?理想情况下,我不想在 XML 中定义 ConnectionFactory 实例,因为它们是动态的并且存储在数据库中。

4

2 回答 2

1

我过去也遇到过类似的问题。Spring Social + 多语言站点(example.de、example.fr、...)=> 多个 facebook 应用程序(因为使用 Facebook 应用程序,您只能将用户返回到同一域)。我最终得到了我的自定义版本的 ConnectController(实际上它是 ProviderSignInController)和一个帮助类(我不确定名称、ConnectionSupport 或类似的东西),以便能够在运行时选择正确的 FacebookConnectionFactory。

于 2013-07-08T09:15:05.860 回答
1

我发现创建 CustomConnectionFactoryRegistry 也可以解决问题,并在下游解决问题。下面的推特示例。该解决方案依赖于数据存储库来检索缓存的应用程序租户和 providerId 的 oauth 凭据。

public class CustomConnectionFactoryRegistry implements ConnectionFactoryLocator {

    @Autowired
    private ConnectServiceRepository connectServiceRepository; // get the credentials for the tenant

    private final Map<Class<?>, String> apiTypeIndex = new HashMap<Class<?>, String>();

    public CustomConnectionFactoryRegistry(){
        apiTypeIndex.put(Twitter.class, "twitter");
    }

    @Override
    public ConnectionFactory<?> getConnectionFactory(String providerId) {
        OAuthApp app = connectServiceFactory.getProviderApp(providerId);
        if (app == null) {
            throw new IllegalArgumentException("No connection factory for service provider '" + providerId + "' is registered");
        }
        OAuth1ConnectionFactory<?> twitterConnectionFactory = new TwitterConnectionFactory(app.getApiKey(),app.getApiSecret());

        return twitterConnectionFactory;        
    }

    @Override
    @SuppressWarnings("unchecked")
    public <A> ConnectionFactory<A> getConnectionFactory(Class<A> apiType) {
        String providerId = apiTypeIndex.get(apiType);
        if (providerId == null) {
            throw new IllegalArgumentException("No connection factory for API [" + apiType.getName() + "] is registered");
        }
        return (ConnectionFactory<A>) getConnectionFactory(providerId);
    }

}
于 2014-08-22T17:49:10.967 回答