위에서 설명한 두 가지 방법을 결합하면 연결할 외부 ID가 있을 때마다 Firebase 프로젝트 간에 인증 데이터를 공유할 수 있습니다.
예를 들어, 앱에서 Google Sign-In을 통한 로그인을 허용하고 기본 프로젝트 및 보조 프로젝트에서 인증을 요구하는 데이터베이스 규칙을 구성한 경우 동일한 Google 자격 증명을 사용하여 두 시스템 모두에 로그인할 수 있습니다.
먼저
평소와 같이 기본 프로젝트에서 Google Sign-In을 사용하도록 앱을 설정합니다. 그러면 기본 프로젝트에서 기본 클라이언트 ID를 얻게 됩니다. 클라이언트 ID는 지정된 앱 클라이언트(웹, Android, iOS)의 식별자일 뿐이며, 보통 클라이언트 자체에 포함되어 있습니다. 한 프로젝트의 클라이언트 ID가 여러 개일 수 있지만,
GoogleSignInOptions builder에 대한 requestIdToken 호출에 지정된 항목을 허용 목록에 추가해야 합니다.
.requestIdToken(getString(R.string.default_web_client_id))
보통 google-services.json에서 유형이 "3"인 첫 번째 client_id로 이 항목을 찾을 수 있습니다. 제 경우엔 다음과 같았습니다.
{
"client_id": "56865680640-e8mr503bun5eaevqctn4u807q4hpi44s.apps.googleusercontent.com",
"client_type": 3
},
이제
Auth > Sign In Providers 섹션의
Google 패널(
보조 프로젝트에 있음)로 이동합니다. 여기서 클라이언트 ID를 허용 목록에 추가할 수 있습니다.
이제 Google Sign-In 결과에서 동일한
GoogleSignInAccount 객체를 가져와서 기본 앱과 보조 앱에 대해 모두 인증할 수 있습니다.
AuthCredential credential = GoogleAuthProvider.getCredential(account.getIdToken(), null);
FirebaseAuth.getInstance().signInWithCredential(credential);
FirebaseApp app = FirebaseApp.getInstance("secondary");
FirebaseAuth.getInstance(app).signInWithCredential(credential);
사용자가 한 번만 로그인해도 두 프로젝트에 대해 모두 인증됩니다.
프로젝트 간 UID 공유
여기서 한 가지 문제점은 각 프로젝트에서 Firebase 사용자 ID가 다르다는 점입니다. 예를 들어, 동일한 Google 자격 증명을 사용하는 경우 다음과 같은 두 가지 UID를 얻습니다.
Default Auth UID: 0960868722032022577213DA4EA8B7A1683D92B405DD
Secondary Auth UID: 7h6XOeSxmkNsSseFJ1jU31WZHDP2
앱이
계정 링크 기능을 제공하지 않으면 데이터베이스 구조 및 보안 규칙 등에 Google(또는 Facebook, Twitter 등) 사용자 ID를 사용할 수 있습니다. 하지만 각 프로젝트에 똑같은 사용자 ID를 사용해야 하거나 이메일/비밀번호 또는 익명 인증을 사용하는 경우 상황은 약간 더 까다롭습니다.
다행히도, 사용자설정 인증 토큰이 자체 UID를 지정하므로 서버 측 코드와 함께 사용자설정 인증 기능으로 이 문제를 해결할 수 있습니다.
이번에는 보조 프로젝트에서 어떠한 항목도 허용 목록에 추가하지 않지만, 보조 프로젝트와 기본 프로젝트 모두의
서비스 계정을 다운로드합니다. 우선, Android 클라이언트에서 로그인하여 FirebaseAuth 클라이언트에서 Firebase ID 토큰을 가져옵니다.
참고: 여기서는 원하는 로그인 제공자를 사용할 수 있습니다. 그냥 사용자설정 토큰을 사용해 프로젝트 전체에 걸쳐 사용자 ID를 연결하겠습니다.
firebaseAuth.getCurrentUser().getToken(false /* forceRefresh */)
.addOnCompleteListener(new OnCompleteListener() {
@Override
public void onComplete(@NonNull Task task) {
String token = task.getResult().getToken(); // Send this to the server.
}
});
토큰을 서버로 보내고 이 토큰으로 Firebase 사용자설정 토큰을 생성합니다. 현재 서버 측에 있기 때문에 서비스 계정을 사용하고는 있지만 Android에서와 마찬가지로 각각의 앱을 초기화해야 합니다(여기서는 Java 서버 SDK를 사용하지만 NodeJS도 이와 마찬가지로 사용할 수 있음).
FirebaseOptions options = new FirebaseOptions.Builder()
.setServiceAccount(new FileInputStream("default-service-account.json"))
.build();
FirebaseApp.initializeApp(options);
FirebaseOptions secondaryOptions = new FirebaseOptions.Builder()
.setServiceAccount(new FileInputStream("secondary-service-account.json"))
.build();
FirebaseApp.initializeApp(secondaryOptions, "secondary");
기본 앱은 클라이언트에서 오는 토큰을 인증하는 데 사용하고 보조 앱은 적당한 UID 세트로 사용자설정 인증 토큰을 생성하는 데 사용합니다.
// Verify the ID token using the default app.
FirebaseAuth.getInstance().verifyIdToken(idToken)
.addOnSuccessListener(new OnSuccessListener() {
@Override
public void onSuccess(FirebaseToken decodedToken) {
String uid = decodedToken.getUid();
System.out.println("User " + uid + " verified");
FirebaseApp app = FirebaseApp.getInstance("secondary");
String customToken = FirebaseAuth.getInstance(app).createCustomToken(uid);
// TODO: Send the token back to the client!
}
});
Android 앱으로 돌아가서, 서버에서 사용자설정 토큰을 가져와서 이를 사용해 보조 프로젝트를 인증합니다.
FirebaseApp app = FirebaseApp.getInstance("secondary");
FirebaseAuth.getInstance(app).signInWithCustomToken(token);
이제, 두 프로젝트의 Firebase UID가 일치합니다.
Default Auth UID: 0960868722032022577213DA4EA8B7A1683D92B405DD
Secondary Auth UID: 0960868722032022577213DA4EA8B7A1683D92B405DD
iOS와 웹도 마찬가지
오늘 설명해드린 내용이 단일 앱에서 여러 Firebase 프로젝트를 다룰 때 유용한 옵션으로 활용할 수 있길 바라겠습니다. iOS와 웹에도 이런 사항이 적용되는지 궁금하시다면 확실히 그렇다고 말씀드릴 수 있습니다. Android의 FirebaseApp에 상응하는 앱을 사용하여 보조 프로젝트에 대한 참조를 생성하기만 하면 됩니다.
JavaScript에서는
firebase.app을 사용합니다.
var config = {
apiKey: "",
authDomain: ".firebaseapp.com",
databaseURL: "https://.firebaseio.com",
storageBucket: ".appspot.com",
messagingSenderId: "",
};
var secondary = firebase.initializeApp(otherAppConfig, "secondary");
var secondaryDatabase = secondary.database();
iOS에서는
FIRApp을 사용합니다.
// Alt: load from plist using |FIROptions(contentsOfFile:)|
let options = FIROptions(googleAppID: googleAppID, bundleID: bundleID, GCMSenderID: GCMSenderID, APIKey: nil, clientID: nil, trackingID: nil, androidClientID: nil, databaseURL: databaseURL, storageBucket: nil, deepLinkURLScheme: nil)
FIRApp.configure(withName: "secondary", options: fileopts)
guard let secondary = FIRApp.init(named: "secondary")
else { assert(false, "Could not retrieve secondary app") }
let secondaryDatabase = FIRDatabase.database(app: secondary);
자세한 내용과 관련 링크는 Firebase 문서에 새로 추가된
Configuring Your Firebase Project(Firebase 프로젝트 구성) 페이지를 살펴보시기 바랍니다.