我正在构建一个支持多个租户的Spring Social应用程序。应用程序根据网址识别租户(例如,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();
}
我考虑过创建一个ConnectInterceptor并在preConnect()步骤中将相关的租户凭证注入到提供的ConnectionFactory实例中,但我怀疑,由于共享了connectionFactory实例,因此无法在多线程Web应用程序中使用。
所以,我的下一个想法就是为每个租户创建一个唯一的ConnectionFactoryRegistry实例。这解决了上述问题。
然后问题转移到ConnectController(Spring的OAuth舞蹈控制器)。由于应用程序只能有一个控制器,并且控制器只有一个注册表,我如何指示控制器使用基于租户的正确注册表?
构建多租户Spring Social应用程序的正确方法是什么,该应用程序将为每个租户支持唯一的ConnectionFactory实例?理想情况下,我不想在XML中定义ConnectionFactory实例,因为它们是动态的并存储在数据库中。
答案 0 :(得分:1)
我过去遇到过类似的问题。 Spring Social +多语言网站(example.de,example.fr,...)=&gt;多个Facebook应用程序(因为使用Facebook应用程序,您只能将用户返回到同一个域)。我最终得到了我的自定义版本的ConnectController(实际上它是ProviderSignInController)和一个助手类(我不确定名称,ConnectionSupport或类似的东西),以便能够在运行时选择正确的FacebookConnectionFactory。
答案 1 :(得分:1)
我发现创建一个CustomConnectionFactoryRegistry也可以解决这个问题并解决下游的问题。 Twitter的例子如下。该解决方案依赖于数据存储库来检索缓存的应用程序租户和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);
}
}