【发布时间】:2017-11-22 16:25:48
【问题描述】:
我有一个播放框架项目,提供在多个前端之间共享的 API,目前,我正在开发单个前端,但我想创建一个多租户后端,每个前端都有自己的 Firebase帐户。
我必须考虑访问哪个 firebase 项目的问题取决于请求标头值,而不同的值则取决于前端。
我现在拥有的: FirebaseAppProvider.java:
public class FirebaseAppProvider implements Provider<FirebaseApp> {
private final Logger.ALogger logger;
private final Environment environment;
private final Configuration configuration;
@Inject
public FirebaseAppProvider(Environment environment, Configuration configuration) {
this.logger = Logger.of(this.getClass());
this.environment = environment;
this.configuration = configuration;
}
@Singleton
@Override
public FirebaseApp get() {
HashMap<String, String> firebaseProjects = (HashMap<String, String>) configuration.getObject("firebase");
firebaseProjects.forEach((websiteId, projectId) -> {
FileInputStream serviceAccount = null;
try {
serviceAccount = new FileInputStream(environment.classLoader().getResource(String.format("firebase/%s.json", projectId)).getPath());
} catch (FileNotFoundException e) {
e.printStackTrace();
return;
}
FirebaseOptions options = new FirebaseOptions.Builder().setCredential(FirebaseCredentials.fromCertificate(serviceAccount))
.setDatabaseUrl(String.format("https://%s.firebaseio.com/", projectId))
.build();
FirebaseApp firebaseApp = FirebaseApp.initializeApp(options, projectId);
logger.info("FirebaseApp initialized");
});
return FirebaseApp.getInstance();
}
}
也适用于数据库: FirebaseDatabaseProvider.java
public class FirebaseDatabaseProvider implements Provider<FirebaseDatabase> {
private final FirebaseApp firebaseApp;
public static List<TaxItem> TAXES = new ArrayList<>();
@Inject
public FirebaseDatabaseProvider(FirebaseApp firebaseApp) {
this.firebaseApp = firebaseApp;
fetchTaxes();
}
@Singleton
@Override
public FirebaseDatabase get() {
return FirebaseDatabase.getInstance(firebaseApp);
}
@Singleton
public DatabaseReference getUserDataReference() {
return this.get().getReference("/usersData");
}
@Singleton
public DatabaseReference getTaxesConfigurationReference() {
return this.get().getReference("/appData/taxConfiguration");
}
private void fetchTaxes() {
DatabaseReference bundlesRef = getTaxesConfigurationReference().child("taxes");
bundlesRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
TAXES.clear();
dataSnapshot.getChildren().forEach(tax -> TAXES.add(tax.getValue(TaxItem.class)));
Logger.info(String.format("==> %d taxes records loaded", TAXES.size()));
}
@Override
public void onCancelled(DatabaseError databaseError) {
Logger.warn("The read failed: " + databaseError.getCode());
}
});
}
}
所以我也从 Module.java 绑定它们:
public class Module extends AbstractModule {
@Override
public void configure() { bind(FirebaseApp.class).toProvider(FirebaseAppProvider.class).asEagerSingleton();
bind(FirebaseAuth.class).toProvider(FirebaseAuthProvider.class).asEagerSingleton();
bind(FirebaseDatabase.class).toProvider(FirebaseDatabaseProvider.class).asEagerSingleton();
}
}
我的 ActionCreator:
public class ActionCreator implements play.http.ActionCreator {
@Inject
public ActionCreator() {
}
@Override
public Action createAction(Http.Request request, Method actionMethod) {
switchTenancyId(request);
return new Action.Simple() {
@Override
public CompletionStage<Result> call(Http.Context ctx) {
return delegate.call(ctx);
}
};
}
private void switchTenancyId(Http.RequestHeader request) {
// DO something here
}
private Optional<String> getTenancyId(Http.RequestHeader request) {
String websiteId = request.getHeader("Website-ID");
System.out.println(websiteId);
return null;
}
}
我想要的是当我使用数据库服务或身份验证服务时,我阅读了网站 ID 并决定访问哪个 firebase 项目,我真的在这里尝试了这样的解决方案: Multi tenancy with Guice Custom Scopes and Jersey
请注意,我愿意为每个前端使用不同的项目,而不是同一个 firebase 项目。
但是有点丢了,尤其是请求只能从控制器或 ActionCreator 访问,所以我从上面的问题中得到的是通过密钥将提供程序加载到 ThreadLocal 并为每个请求切换它们取决于注释,但我是由于缺乏知识而无法做到这一点。
我的项目的最小化版本可以在这里找到:https://github.com/almothafar/play-with-multi-tenant-firebase
另外,我上传了 taxes-data-export.json 文件以导入到 firebase 项目中进行测试。
【问题讨论】:
标签: java playframework guice multi-tenant