Firebase Summit에서 발표된 모든 내용을 살펴보고 Firebase로 앱을 빠르게 개발하고 안심하고 앱을 실행하는 방법을 알아보세요. 자세히 알아보기

Android에서 이메일 링크를 사용하여 Firebase로 인증

Firebase 인증을 사용하여 사용자가 클릭하여 로그인할 수 있는 링크가 포함된 이메일을 전송하여 로그인할 수 있습니다. 이 과정에서 사용자의 이메일 주소도 확인됩니다.

이메일로 로그인하면 다음과 같은 많은 이점이 있습니다.

  • 마찰이 적은 가입 및 로그인.
  • 잘 선택된 암호의 보안을 약화시킬 수 있는 응용 프로그램 전체에서 암호 재사용 위험을 낮춥니다.
  • 사용자가 이메일 주소의 적법한 소유자인지 확인하는 동시에 사용자를 인증하는 기능입니다.
  • 사용자는 액세스 가능한 이메일 계정만 있으면 로그인할 수 있습니다. 전화번호나 소셜 미디어 계정의 소유권은 필요하지 않습니다.
  • 사용자는 모바일 장치에서 번거로울 수 있는 암호를 제공(또는 기억)할 필요 없이 안전하게 로그인할 수 있습니다.
  • 이전에 이메일 식별자(비밀번호 또는 연합)로 로그인한 기존 사용자는 이메일만으로 로그인하도록 업그레이드할 수 있습니다. 예를 들어 비밀번호를 잊어버린 사용자는 비밀번호를 재설정하지 않고도 로그인할 수 있습니다.

시작하기 전에

Android 프로젝트 설정

  1. 아직 추가하지 않았다면 Android 프로젝트에 Firebase를 추가합니다 .

  2. 모듈(앱 수준) Gradle 파일 (일반적으로 <project>/<app-module>/build.gradle )에서 Firebase 인증 Android 라이브러리에 대한 종속성을 추가합니다. Firebase Android BoM 을 사용하여 라이브러리 버전 관리를 제어하는 ​​것이 좋습니다.

    또한 Firebase 인증 설정의 일부로 앱에 Google Play 서비스 SDK를 추가해야 합니다.

    Kotlin+KTX

    dependencies {
        // Import the BoM for the Firebase platform
        implementation platform('com.google.firebase:firebase-bom:31.2.0')
    
        // Add the dependency for the Firebase Authentication library
        // When using the BoM, you don't specify versions in Firebase library dependencies
        implementation 'com.google.firebase:firebase-auth-ktx'
    // Also add the dependency for the Google Play services library and specify its version implementation 'com.google.android.gms:play-services-auth:20.4.1'
    }

    Firebase Android BoM 을 사용하면 앱에서 항상 호환되는 버전의 Firebase Android 라이브러리를 사용합니다.

    (대안) BoM을 사용 하지 않고 Firebase 라이브러리 종속성 추가

    Firebase BoM을 사용하지 않기로 선택한 경우 종속성 줄에 각 Firebase 라이브러리 버전을 지정해야 합니다.

    앱에서 여러 Firebase 라이브러리를 사용하는 경우 BoM을 사용하여 모든 버전이 호환되도록 라이브러리 버전을 관리하는 것이 좋습니다.

    dependencies {
        // Add the dependency for the Firebase Authentication library
        // When NOT using the BoM, you must specify versions in Firebase library dependencies
        implementation 'com.google.firebase:firebase-auth-ktx:21.1.0'
    // Also add the dependency for the Google Play services library and specify its version implementation 'com.google.android.gms:play-services-auth:20.4.1'
    }

    Java

    dependencies {
        // Import the BoM for the Firebase platform
        implementation platform('com.google.firebase:firebase-bom:31.2.0')
    
        // Add the dependency for the Firebase Authentication library
        // When using the BoM, you don't specify versions in Firebase library dependencies
        implementation 'com.google.firebase:firebase-auth'
    // Also add the dependency for the Google Play services library and specify its version implementation 'com.google.android.gms:play-services-auth:20.4.1'
    }

    Firebase Android BoM 을 사용하면 앱에서 항상 호환되는 버전의 Firebase Android 라이브러리를 사용합니다.

    (대안) BoM을 사용 하지 않고 Firebase 라이브러리 종속성 추가

    Firebase BoM을 사용하지 않기로 선택한 경우 종속성 줄에 각 Firebase 라이브러리 버전을 지정해야 합니다.

    앱에서 여러 Firebase 라이브러리를 사용하는 경우 BoM을 사용하여 모든 버전이 호환되도록 라이브러리 버전을 관리하는 것이 좋습니다.

    dependencies {
        // Add the dependency for the Firebase Authentication library
        // When NOT using the BoM, you must specify versions in Firebase library dependencies
        implementation 'com.google.firebase:firebase-auth:21.1.0'
    // Also add the dependency for the Google Play services library and specify its version implementation 'com.google.android.gms:play-services-auth:20.4.1'
    }

이메일 링크로 사용자를 로그인하려면 먼저 Firebase 프로젝트에 대해 이메일 공급자 및 이메일 링크 로그인 방법을 활성화해야 합니다.

  1. Firebase 콘솔 에서 인증 섹션을 엽니다.
  2. 로그인 방법 탭에서 이메일/암호 공급자를 활성화합니다. 이메일 링크 로그인을 사용하려면 이메일/비밀번호 로그인이 활성화되어 있어야 합니다.
  3. 같은 섹션에서 이메일 링크(암호 없는 로그인) 로그인 방법을 활성화합니다.
  4. 저장 을 클릭합니다.

인증 흐름을 시작하려면 사용자에게 이메일 주소를 제공하라는 메시지를 표시하는 인터페이스를 사용자에게 제시한 다음 sendSignInLinkToEmail 을 호출하여 Firebase가 사용자의 이메일에 인증 링크를 보내도록 요청합니다.

  1. 이메일 링크를 구성하는 방법에 대한 지침을 Firebase에 제공하는 ActionCodeSettings 개체를 구성합니다. 다음 필드를 설정합니다.

    • url : 삽입할 딥 링크 및 전달할 추가 상태입니다. 링크의 도메인은 로그인 방법 탭(인증 -> 로그인 방법)으로 이동하여 찾을 수 있는 승인된 도메인의 Firebase 콘솔 목록에 허용 목록에 있어야 합니다. 앱이 장치에 설치되어 있지 않고 앱을 설치할 수 없는 경우 링크는 사용자를 이 URL로 리디렉션합니다.
    • androidPackageNameIOSBundleId : Android 또는 Apple 장치에서 로그인 링크가 열릴 때 사용할 앱입니다. 모바일 앱을 통해 이메일 작업 링크를 열도록 Firebase 동적 링크를 구성 하는 방법에 대해 자세히 알아보세요.
    • handleCodeInApp : true로 설정합니다. 로그인 작업은 다른 대역 외 이메일 작업(비밀번호 재설정 및 이메일 확인)과 달리 항상 앱에서 완료해야 합니다. 이는 흐름이 끝날 때 사용자가 로그인하고 인증 상태가 앱 내에서 유지될 것으로 예상되기 때문입니다.
    • dynamicLinkDomain : 프로젝트에 대해 여러 사용자 지정 동적 링크 도메인이 정의된 경우 지정된 모바일 앱(예: example.page.link )을 통해 링크를 열 때 사용할 도메인을 지정합니다. 그렇지 않으면 첫 번째 도메인이 자동으로 선택됩니다.

    Kotlin+KTX

    val actionCodeSettings = actionCodeSettings {
        // URL you want to redirect back to. The domain (www.example.com) for this
        // URL must be whitelisted in the Firebase Console.
        url = "https://www.example.com/finishSignUp?cartId=1234"
        // This must be true
        handleCodeInApp = true
        setIOSBundleId("com.example.ios")
        setAndroidPackageName(
                "com.example.android",
                true, /* installIfNotAvailable */
                "12" /* minimumVersion */)
    }

    Java

    ActionCodeSettings actionCodeSettings =
            ActionCodeSettings.newBuilder()
                    // URL you want to redirect back to. The domain (www.example.com) for this
                    // URL must be whitelisted in the Firebase Console.
                    .setUrl("https://www.example.com/finishSignUp?cartId=1234")
                    // This must be true
                    .setHandleCodeInApp(true)
                    .setIOSBundleId("com.example.ios")
                    .setAndroidPackageName(
                            "com.example.android",
                            true, /* installIfNotAvailable */
                            "12"    /* minimumVersion */)
                    .build();

    ActionCodeSettings에 대한 자세한 내용 은 이메일 작업 섹션의 전달 상태를 참조하십시오.

  2. 사용자에게 이메일을 요청합니다.

  3. 인증 링크를 사용자의 이메일로 전송하고 사용자가 동일한 기기에서 이메일 로그인을 완료한 경우 사용자의 이메일을 저장합니다.

    Kotlin+KTX

    Firebase.auth.sendSignInLinkToEmail(email, actionCodeSettings)
            .addOnCompleteListener { task ->
                if (task.isSuccessful) {
                    Log.d(TAG, "Email sent.")
                }
            }

    Java

    FirebaseAuth auth = FirebaseAuth.getInstance();
    auth.sendSignInLinkToEmail(email, actionCodeSettings)
            .addOnCompleteListener(new OnCompleteListener<Void>() {
                @Override
                public void onComplete(@NonNull Task<Void> task) {
                    if (task.isSuccessful()) {
                        Log.d(TAG, "Email sent.");
                    }
                }
            });

보안 문제

로그인 링크가 의도하지 않은 사용자 또는 의도하지 않은 기기에 로그인하는 데 사용되는 것을 방지하기 위해 로그인 과정을 완료할 때 Firebase 인증에서 사용자의 이메일 주소를 제공해야 합니다. 로그인에 성공하려면 이 이메일 주소가 로그인 링크가 원래 전송된 주소와 일치해야 합니다.

로그인 이메일을 보낼 때 이메일 주소를 로컬에 저장(예: SharedPreferences 사용)하여 링크를 요청한 동일한 장치에서 로그인 링크를 여는 사용자를 위해 이 흐름을 간소화할 수 있습니다. 그런 다음 이 주소를 사용하여 흐름을 완료합니다. 세션 삽입을 활성화할 수 있으므로 리디렉션 URL 매개 변수에 사용자의 이메일을 전달하고 재사용하지 마십시오.

로그인이 완료되면 이전의 확인되지 않은 로그인 메커니즘이 사용자에게서 제거되고 기존 세션이 무효화됩니다. 예를 들어 누군가 이전에 동일한 이메일과 비밀번호로 확인되지 않은 계정을 만든 경우 소유권을 주장하고 해당 확인되지 않은 계정을 만든 명의 도용자가 확인되지 않은 이메일과 비밀번호로 다시 로그인하지 못하도록 사용자의 비밀번호가 제거됩니다.

또한 중개 서버에서 링크를 잠재적으로 가로채지 않도록 프로덕션 환경에서 HTTPS URL을 사용해야 합니다.

Android 앱에서 로그인 완료

Firebase 인증은 Firebase 동적 링크를 사용하여 모바일 장치에 이메일 링크를 보냅니다. 모바일 애플리케이션을 통해 로그인을 완료하려면 수신 애플리케이션 링크를 감지하고 기본 딥 링크를 구문 분석한 다음 로그인을 완료하도록 애플리케이션을 구성해야 합니다.

Firebase 인증은 모바일 애플리케이션에서 열려는 링크를 보낼 때 Firebase 동적 링크 를 사용합니다. 이 기능을 사용하려면 Firebase 콘솔에서 동적 링크를 구성 해야 합니다 .

  1. Firebase 동적 링크 활성화:

    1. Firebase 콘솔 에서 동적 링크 섹션을 엽니다.
    2. 아직 동적 링크 약관에 동의하지 않았고 동적 링크 도메인을 생성하지 않았다면 지금 수행하십시오.

      동적 링크 도메인을 이미 만든 경우 기록해 둡니다. 동적 링크 도메인은 일반적으로 다음 예와 같습니다.

      example.page.link

      수신 링크를 가로채도록 Apple 또는 Android 앱을 구성할 때 이 값이 필요합니다.

  2. Android 애플리케이션 구성:

    1. Android 애플리케이션에서 이러한 링크를 처리하려면 Firebase 콘솔 프로젝트 설정에서 Android 패키지 이름을 지정해야 합니다. 또한 애플리케이션 인증서의 SHA-1 및 SHA-256을 제공해야 합니다.
    2. 이제 동적 링크 도메인을 추가하고 Android 앱이 올바르게 구성되었는지 확인했으므로 동적 링크는 런처 활동에서 시작하여 애플리케이션으로 리디렉션됩니다.
    3. 동적 링크를 특정 활동으로 리디렉션하려면 AndroidManifest.xml 파일에서 인텐트 필터를 구성해야 합니다. 이는 인텐트 필터에서 동적 링크 도메인 또는 이메일 작업 핸들러를 지정하여 수행할 수 있습니다. 기본적으로 이메일 작업 핸들러는 다음 예와 같은 도메인에서
      PROJECT_ID.firebaseapp.com/
      됩니다.
    4. 주의 사항:
      1. 의도 필터의 actionCodeSettings에 설정한 URL을 지정하지 마십시오.
      2. 동적 링크 도메인을 생성할 때 짧은 URL 링크도 생성했을 수 있습니다. 이 단축 URL은 전달되지 않습니다. android:pathPrefix 속성으로 인텐트 필터를 포착하도록 구성 하지 마세요 . 이는 애플리케이션의 다른 부분에서 다른 동적 링크를 포착할 수 없음을 의미합니다. 그러나 링크의 mode 쿼리 매개변수 확인하여 어떤 작업을 수행하려고 하는지 확인하거나 isSignInWithEmailLink 와 같은 SDK 메서드를 사용하여 앱이 수신한 링크가 원하는 작업을 수행하는지 확인할 수 있습니다.
    5. 동적 링크 수신에 대한 자세한 내용은 Android 동적 링크 수신 지침 을 참조하십시오.

위에서 설명한 대로 링크를 수신한 후 이메일 링크 인증을 위한 것인지 확인하고 로그인을 완료합니다.

Kotlin+KTX

val auth = Firebase.auth
val intent = intent
val emailLink = intent.data.toString()

// Confirm the link is a sign-in with email link.
if (auth.isSignInWithEmailLink(emailLink)) {
    // Retrieve this from wherever you stored it
    val email = "someemail@domain.com"

    // The client SDK will parse the code from the link for you.
    auth.signInWithEmailLink(email, emailLink)
            .addOnCompleteListener { task ->
                if (task.isSuccessful) {
                    Log.d(TAG, "Successfully signed in with email link!")
                    val result = task.result
                    // You can access the new user via result.getUser()
                    // Additional user info profile *not* available via:
                    // result.getAdditionalUserInfo().getProfile() == null
                    // You can check if the user is new or existing:
                    // result.getAdditionalUserInfo().isNewUser()
                } else {
                    Log.e(TAG, "Error signing in with email link", task.exception)
                }
            }
}

Java

FirebaseAuth auth = FirebaseAuth.getInstance();
Intent intent = getIntent();
String emailLink = intent.getData().toString();

// Confirm the link is a sign-in with email link.
if (auth.isSignInWithEmailLink(emailLink)) {
    // Retrieve this from wherever you stored it
    String email = "someemail@domain.com";

    // The client SDK will parse the code from the link for you.
    auth.signInWithEmailLink(email, emailLink)
            .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        Log.d(TAG, "Successfully signed in with email link!");
                        AuthResult result = task.getResult();
                        // You can access the new user via result.getUser()
                        // Additional user info profile *not* available via:
                        // result.getAdditionalUserInfo().getProfile() == null
                        // You can check if the user is new or existing:
                        // result.getAdditionalUserInfo().isNewUser()
                    } else {
                        Log.e(TAG, "Error signing in with email link", task.getException());
                    }
                }
            });
}

Apple 애플리케이션에서 이메일 링크로 로그인을 처리하는 방법에 대해 자세히 알아보려면 Apple 플랫폼 가이드 를 참조하십시오.

웹 애플리케이션에서 이메일 링크로 로그인을 처리하는 방법에 대해 알아보려면 웹 가이드 를 참조하십시오.

이 인증 방법을 기존 사용자에게 연결할 수도 있습니다. 예를 들어 이전에 전화번호와 같은 다른 공급자로 인증된 사용자는 기존 계정에 이 로그인 방법을 추가할 수 있습니다.

차이점은 작업 후반부에 있습니다.

Kotlin+KTX

// Construct the email link credential from the current URL.
val credential = EmailAuthProvider.getCredentialWithLink(email, emailLink)

// Link the credential to the current user.
Firebase.auth.currentUser!!.linkWithCredential(credential)
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                Log.d(TAG, "Successfully linked emailLink credential!")
                val result = task.result
                // You can access the new user via result.getUser()
                // Additional user info profile *not* available via:
                // result.getAdditionalUserInfo().getProfile() == null
                // You can check if the user is new or existing:
                // result.getAdditionalUserInfo().isNewUser()
            } else {
                Log.e(TAG, "Error linking emailLink credential", task.exception)
            }
        }

Java

// Construct the email link credential from the current URL.
AuthCredential credential =
        EmailAuthProvider.getCredentialWithLink(email, emailLink);

// Link the credential to the current user.
auth.getCurrentUser().linkWithCredential(credential)
        .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                    Log.d(TAG, "Successfully linked emailLink credential!");
                    AuthResult result = task.getResult();
                    // You can access the new user via result.getUser()
                    // Additional user info profile *not* available via:
                    // result.getAdditionalUserInfo().getProfile() == null
                    // You can check if the user is new or existing:
                    // result.getAdditionalUserInfo().isNewUser()
                } else {
                    Log.e(TAG, "Error linking emailLink credential", task.getException());
                }
            }
        });

민감한 작업을 실행하기 전에 이메일 링크 사용자를 재인증하는 데 사용할 수도 있습니다.

Kotlin+KTX

// Construct the email link credential from the current URL.
val credential = EmailAuthProvider.getCredentialWithLink(email, emailLink)

// Re-authenticate the user with this credential.
Firebase.auth.currentUser!!.reauthenticateAndRetrieveData(credential)
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                // User is now successfully reauthenticated
            } else {
                Log.e(TAG, "Error reauthenticating", task.exception)
            }
        }

Java

// Construct the email link credential from the current URL.
AuthCredential credential =
        EmailAuthProvider.getCredentialWithLink(email, emailLink);

// Re-authenticate the user with this credential.
auth.getCurrentUser().reauthenticateAndRetrieveData(credential)
        .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                    // User is now successfully reauthenticated
                } else {
                    Log.e(TAG, "Error reauthenticating", task.getException());
                }
            }
        });

그러나 원래 사용자가 로그인하지 않은 다른 장치에서 흐름이 종료될 수 있으므로 이 흐름이 완료되지 않을 수 있습니다. 이 경우 사용자에게 동일한 장치에서 링크를 열도록 강제하는 오류가 표시될 수 있습니다. 작업 유형 및 사용자 uid에 대한 정보를 제공하기 위해 링크에서 일부 상태를 전달할 수 있습니다.

이메일로 비밀번호 및 링크 기반 로그인을 모두 지원하는 경우 비밀번호/링크 사용자의 로그인 방법을 구분하려면 fetchSignInMethodsForEmail 을 사용하세요. 이는 사용자에게 먼저 이메일을 제공하라는 요청을 받은 다음 로그인 방법이 제시되는 식별자 우선 흐름에 유용합니다.

Kotlin+KTX

Firebase.auth.fetchSignInMethodsForEmail(email)
        .addOnSuccessListener { result ->
            val signInMethods = result.signInMethods!!
            if (signInMethods.contains(EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD)) {
                // User can sign in with email/password
            } else if (signInMethods.contains(EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD)) {
                // User can sign in with email/link
            }
        }
        .addOnFailureListener { exception ->
            Log.e(TAG, "Error getting sign in methods for user", exception)
        }

Java

auth.fetchSignInMethodsForEmail(email)
        .addOnCompleteListener(new OnCompleteListener<SignInMethodQueryResult>() {
            @Override
            public void onComplete(@NonNull Task<SignInMethodQueryResult> task) {
                if (task.isSuccessful()) {
                    SignInMethodQueryResult result = task.getResult();
                    List<String> signInMethods = result.getSignInMethods();
                    if (signInMethods.contains(EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD)) {
                        // User can sign in with email/password
                    } else if (signInMethods.contains(EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD)) {
                        // User can sign in with email/link
                    }
                } else {
                    Log.e(TAG, "Error getting sign in methods for user", task.getException());
                }
            }
        });

위에서 설명한 것처럼 이메일/비밀번호 및 이메일/링크는 로그인 방법이 다른 동일한 EmailAuthProvider (동일한 PROVIDER_ID )로 간주됩니다.

다음 단계

사용자가 처음으로 로그인하면 새 사용자 계정이 생성되고 사용자가 로그인할 때 사용한 자격 증명(즉, 사용자 이름과 암호, 전화 번호 또는 인증 공급자 정보)에 연결됩니다. 이 새 계정은 Firebase 프로젝트의 일부로 저장되며 사용자 로그인 방법에 관계없이 프로젝트의 모든 앱에서 사용자를 식별하는 데 사용할 수 있습니다.

  • 앱에서 FirebaseUser 개체에서 사용자의 기본 프로필 정보를 가져올 수 있습니다. 사용자 관리 를 참조하십시오.

  • Firebase 실시간 데이터베이스 및 Cloud Storage 보안 규칙 에서 auth 변수에서 로그인한 사용자의 고유한 사용자 ID를 가져와 사용자가 액세스할 수 있는 데이터를 제어하는 ​​데 사용할 수 있습니다.

인증 공급자 자격 증명을 기존 사용자 계정에 연결하여 사용자가 여러 인증 공급자를 사용하여 앱에 로그인하도록 허용할 수 있습니다.

사용자를 로그아웃하려면 signOut 을 호출합니다.

Kotlin+KTX

Firebase.auth.signOut()

Java

FirebaseAuth.getInstance().signOut();