Kakao·LINE 로그인을 Firebase OIDC 제공자로 연결 · 계정 연결
This commit is contained in:
@@ -199,31 +199,87 @@ final class AppleSignInProvider
|
||||
kIsWeb || defaultTargetPlatform == TargetPlatform.android;
|
||||
}
|
||||
|
||||
/// 발주사 키를 기다리는 제공자 — 카카오·LINE.
|
||||
/// 카카오·LINE — Firebase Auth 의 OpenID Connect 제공자(`oidc.kakao` · `oidc.line`).
|
||||
///
|
||||
/// 예외를 던지지 않는다. [AuthNotConfigured] 로 "무엇이 없어서 못 쓰는지"를 돌려주고
|
||||
/// 로그인 화면이 그걸 안내 다이얼로그로 띄운다. 키가 들어오면 이 자리에 실 구현체를
|
||||
/// 넣고 [AuthRepository] 목록만 바꾸면 된다 — 화면·라우터는 그대로다.
|
||||
final class KeylessSocialProvider implements SocialAuthProvider {
|
||||
const KeylessSocialProvider(this.provider, this.missingConfig);
|
||||
/// 두 회사 모두 OIDC 표준(issuer `https://kauth.kakao.com` · `https://access.line.me`)을
|
||||
/// 지원해 Firebase 가 코드 교환·ID 토큰 검증까지 맡는다. 앱은 SDK 없이
|
||||
/// `signInWithProvider` 하나로 끝난다 — Android 는 Custom Tabs, iOS 는
|
||||
/// SFSafariViewController 로 인가 화면을 띄우고 Firebase 핸들러
|
||||
/// (`https://<프로젝트>.firebaseapp.com/__/auth/handler`)로 돌아온다.
|
||||
/// iOS 콜백 스킴은 Google 로그인용 REVERSED_CLIENT_ID 를 같이 쓴다.
|
||||
///
|
||||
/// 콘솔에서 제공자를 켜지 않았으면 Firebase 가 `operation-not-allowed` 를 돌려주고
|
||||
/// [authCatalogCode] 가 E-AUTH-11 로 옮긴다 — 앱이 따로 플래그를 들 필요가 없다.
|
||||
///
|
||||
/// [CredentialProvider] 가 아니다. 웹 흐름이 자격증명 발급과 로그인·연결을 한 번에
|
||||
/// 끝내서 자격증명만 먼저 받아 볼 수 없다. 계정 연결은 [FirebaseAccountLinker] 가
|
||||
/// [authProvider] 로 `linkWithProvider` 를 부른다.
|
||||
final class OidcSignInProvider implements SocialAuthProvider {
|
||||
const OidcSignInProvider(
|
||||
this.provider, {
|
||||
required this.providerId,
|
||||
this.scopes = const [],
|
||||
this.firebaseAuth,
|
||||
});
|
||||
|
||||
@override
|
||||
final SocialProvider provider;
|
||||
|
||||
@override
|
||||
final List<String> missingConfig;
|
||||
/// Firebase 콘솔에 등록한 제공자 ID. `oidc.` 접두는 콘솔이 강제한다.
|
||||
final String providerId;
|
||||
|
||||
/// `openid` 외에 더 받을 항목. Firebase 가 `openid` 는 알아서 붙인다.
|
||||
/// **콘솔에 켠 동의 항목과 맞아야 한다** — 카카오는 설정에 없는 scope 를 요청하면
|
||||
/// KOE205 로 로그인 자체를 막는다.
|
||||
final List<String> scopes;
|
||||
|
||||
/// 테스트 주입용. 기본은 [fb.FirebaseAuth.instance].
|
||||
final fb.FirebaseAuth? firebaseAuth;
|
||||
|
||||
@override
|
||||
bool get isLive => false;
|
||||
bool get isLive => true;
|
||||
|
||||
@override
|
||||
Future<AuthOutcome> signIn() async =>
|
||||
AuthNotConfigured(provider, missingConfig);
|
||||
List<String> get missingConfig =>
|
||||
FirebaseBoot.isLive ? const [] : FirebaseBoot.missingLabels;
|
||||
|
||||
fb.OAuthProvider get authProvider {
|
||||
final p = fb.OAuthProvider(providerId);
|
||||
for (final scope in scopes) {
|
||||
p.addScope(scope);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> signOut() async {}
|
||||
Future<AuthOutcome> signIn() async {
|
||||
final missing = missingConfig;
|
||||
if (missing.isNotEmpty) return AuthNotConfigured(provider, missing);
|
||||
try {
|
||||
final result = await (firebaseAuth ?? fb.FirebaseAuth.instance)
|
||||
.signInWithProvider(authProvider);
|
||||
return AuthSucceeded(_toAccount(result.user, provider));
|
||||
} on fb.FirebaseAuthException catch (error) {
|
||||
if (isWebFlowCancelled(error)) return const AuthCancelled();
|
||||
return AuthFailed(
|
||||
authCatalogCode(error),
|
||||
authMessage(error, flow: AuthFlow.signIn),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> signOut() async {
|
||||
// 카카오·LINE 쪽 세션은 브라우저 쿠키라 앱이 지울 수 없다. Firebase 세션은
|
||||
// AuthSession 이 닫는다.
|
||||
}
|
||||
}
|
||||
|
||||
/// 사용자가 인가 웹 화면을 닫았다. Android 는 `canceled`, iOS 는 `cancelled` 철자다.
|
||||
bool isWebFlowCancelled(fb.FirebaseAuthException error) =>
|
||||
error.code == 'web-context-canceled' ||
|
||||
error.code == 'web-context-cancelled';
|
||||
|
||||
/// Apple Service ID와 callback URL은 비밀값이 아니지만 환경별 값이다.
|
||||
/// 저장소에 임시 상수를 박지 않고 빌드 시 `--dart-define`으로만 받는다.
|
||||
apple.WebAuthenticationOptions? appleWebAuthenticationOptionsFromEnvironment() {
|
||||
@@ -337,14 +393,6 @@ final class EmailPasswordProvider implements EmailAuthProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/// LINE — 발주사 키 대기.
|
||||
///
|
||||
/// 별첨 B v1.4 확정 4종에 LINE 이 있고 네이버·X 는 없다.
|
||||
const lineProvider = KeylessSocialProvider(AuthProviderKind.line, [
|
||||
'LINE Login 채널 ID / 채널 시크릿',
|
||||
'LINE Developers 콘솔 채널 등록(사업자 정보 필요)',
|
||||
]);
|
||||
|
||||
/// SDK 코드를 에러 카탈로그 ID 로 옮긴다.
|
||||
///
|
||||
/// **계정 존재 여부를 드러내지 않는다.** 「등록되지 않은 이메일」과 「비밀번호
|
||||
|
||||
Reference in New Issue
Block a user