Аутентификация с помощью OpenID Connect на Android

Если вы перешли на Firebase Authentication with Identity Platform , вы можете аутентифицировать своих пользователей в Firebase, используя поставщика, совместимого с OpenID Connect (OIDC), по вашему выбору. Это позволяет использовать поставщиков удостоверений, которые изначально не поддерживаются Firebase.

Прежде чем начать

Чтобы выполнить вход пользователей с помощью поставщика OIDC, необходимо сначала получить от поставщика некоторую информацию:

  • Идентификатор клиента : строка, уникальная для поставщика, идентифицирующая ваше приложение. Ваш провайдер может назначить вам другой идентификатор клиента для каждой поддерживаемой вами платформы. Это одно из значений утверждения aud в токенах идентификатора, выданных вашим провайдером.

  • Секрет клиента : секретная строка, которую провайдер использует для подтверждения владения идентификатором клиента. Для каждого идентификатора клиента вам понадобится соответствующий секрет клиента. (Это значение требуется только в том случае, если вы используете поток кода аутентификации , что настоятельно рекомендуется.)

  • Эмитент : строка, идентифицирующая вашего провайдера. Это значение должно быть URL-адресом, который при добавлении к нему /.well-known/openid-configuration является расположением документа обнаружения OIDC поставщика. Например, если эмитентом является https://auth.example.com , документ обнаружения должен быть доступен по адресу https://auth.example.com/.well-known/openid-configuration .

Получив вышеуказанную информацию, включите OpenID Connect в качестве поставщика входа в свой проект Firebase:

  1. Добавьте Firebase в свой проект Android .

  2. Если вы еще не перешли на Firebase Authentication with Identity Platform , сделайте это. Аутентификация OpenID Connect доступна только в обновленных проектах.

  3. На странице «Поставщики входа» в консоли Firebase нажмите «Добавить нового поставщика» , а затем нажмите «OpenID Connect» .

  4. Выберите, будете ли вы использовать поток кода авторизации или поток неявного предоставления .

    Вам следует всегда использовать поток кода, если ваш провайдер его поддерживает . Неявный поток менее безопасен, и его использование настоятельно не рекомендуется.

  5. Дайте имя этому провайдеру. Обратите внимание на сгенерированный идентификатор провайдера: что-то вроде oidc.example-provider . Этот идентификатор понадобится вам, когда вы добавите код входа в свое приложение.

  6. Укажите идентификатор и секрет клиента, а также строку эмитента вашего провайдера. Эти значения должны точно соответствовать значениям, назначенным вам вашим провайдером.

  7. Сохраните изменения.

Управляйте процессом входа в систему с помощью Firebase SDK

Если вы создаете приложение для Android, самый простой способ аутентификации ваших пользователей в Firebase с помощью вашего провайдера OIDC — это обработка всего процесса входа в систему с помощью Firebase Android SDK.

Чтобы обработать процесс входа с помощью Firebase Android SDK, выполните следующие действия:

  1. Создайте экземпляр OAuthProvider , используя его Builder с идентификатором поставщика.

    Kotlin

    val providerBuilder = OAuthProvider.newBuilder("oidc.example-provider")

    Java

    OAuthProvider.Builder providerBuilder = OAuthProvider.newBuilder("oidc.example-provider");

  2. Необязательно : укажите дополнительные пользовательские параметры OAuth, которые вы хотите отправить с запросом OAuth.

    Kotlin

    // Target specific email with login hint.
    providerBuilder.addCustomParameter("login_hint", "user@example.com")

    Java

    // Target specific email with login hint.
    providerBuilder.addCustomParameter("login_hint", "user@example.com");

    Уточните у своего поставщика OIDC параметры, которые он поддерживает. Обратите внимание, что вы не можете передавать параметры, необходимые для Firebase, с помощью setCustomParameters() . Этими параметрами являются client_id , тип_ответа , redirect_uri , состояние , область действия и режим_ответа .

  3. Необязательно : укажите дополнительные области OAuth 2.0 помимо базового профиля, которые вы хотите запросить у поставщика аутентификации.

    Kotlin

    // Request read access to a user's email addresses.
    // This must be preconfigured in the app's API permissions.
    providerBuilder.scopes = listOf("mail.read", "calendars.read")

    Java

    // Request read access to a user's email addresses.
    // This must be preconfigured in the app's API permissions.
    List<String> scopes =
            new ArrayList<String>() {
                {
                    add("mail.read");
                    add("calendars.read");
                }
            };
    providerBuilder.setScopes(scopes);

    Узнайте у своего поставщика OIDC области действия, которые они используют.

  4. Аутентификация в Firebase с использованием объекта провайдера OAuth. Обратите внимание, что в отличие от других операций FirebaseAuth, эта операция возьмет на себя управление вашим пользовательским интерфейсом, открыв специальную вкладку Chrome . В результате не ссылайтесь на свою активность в прикрепленных вами OnSuccessListener и OnFailureListener , поскольку они немедленно отсоединятся, когда операция запустит пользовательский интерфейс.

    Сначала вам следует проверить, получили ли вы уже ответ. При входе с помощью этого метода ваша активность переходит в фоновый режим, а это означает, что система может вернуть ее во время входа в систему. Чтобы убедиться, что вы не заставите пользователя повторить попытку, если это произойдет, вам следует проверить, присутствует ли уже результат.

    Чтобы проверить, есть ли ожидающий результат, вызовите getPendingAuthResult :

    Kotlin

    val pendingResultTask = firebaseAuth.pendingAuthResult
    if (pendingResultTask != null) {
        // There's something already here! Finish the sign-in for your user.
        pendingResultTask
            .addOnSuccessListener {
                // User is signed in.
                // IdP data available in
                // authResult.getAdditionalUserInfo().getProfile().
                // The OAuth access token can also be retrieved:
                // ((OAuthCredential)authResult.getCredential()).getAccessToken().
                // The OAuth secret can be retrieved by calling:
                // ((OAuthCredential)authResult.getCredential()).getSecret().
            }
            .addOnFailureListener {
                // Handle failure.
            }
    } else {
        // There's no pending result so you need to start the sign-in flow.
        // See below.
    }

    Java

    Task<AuthResult> pendingResultTask = firebaseAuth.getPendingAuthResult();
    if (pendingResultTask != null) {
        // There's something already here! Finish the sign-in for your user.
        pendingResultTask
                .addOnSuccessListener(
                        new OnSuccessListener<AuthResult>() {
                            @Override
                            public void onSuccess(AuthResult authResult) {
                                // User is signed in.
                                // IdP data available in
                                // authResult.getAdditionalUserInfo().getProfile().
                                // The OAuth access token can also be retrieved:
                                // ((OAuthCredential)authResult.getCredential()).getAccessToken().
                                // The OAuth secret can be retrieved by calling:
                                // ((OAuthCredential)authResult.getCredential()).getSecret().
                            }
                        })
                .addOnFailureListener(
                        new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                // Handle failure.
                            }
                        });
    } else {
        // There's no pending result so you need to start the sign-in flow.
        // See below.
    }

    Чтобы запустить процесс входа, вызовите startActivityForSignInWithProvider :

    Kotlin

    firebaseAuth
        .startActivityForSignInWithProvider(activity, provider.build())
        .addOnSuccessListener {
            // User is signed in.
            // IdP data available in
            // authResult.getAdditionalUserInfo().getProfile().
            // The OAuth access token can also be retrieved:
            // ((OAuthCredential)authResult.getCredential()).getAccessToken().
            // The OAuth secret can be retrieved by calling:
            // ((OAuthCredential)authResult.getCredential()).getSecret().
        }
        .addOnFailureListener {
            // Handle failure.
        }

    Java

    firebaseAuth
            .startActivityForSignInWithProvider(/* activity= */ this, provider.build())
            .addOnSuccessListener(
                    new OnSuccessListener<AuthResult>() {
                        @Override
                        public void onSuccess(AuthResult authResult) {
                            // User is signed in.
                            // IdP data available in
                            // authResult.getAdditionalUserInfo().getProfile().
                            // The OAuth access token can also be retrieved:
                            // ((OAuthCredential)authResult.getCredential()).getAccessToken().
                            // The OAuth secret can be retrieved by calling:
                            // ((OAuthCredential)authResult.getCredential()).getSecret().
                        }
                    })
            .addOnFailureListener(
                    new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception e) {
                            // Handle failure.
                        }
                    });

  5. Хотя приведенные выше примеры посвящены потокам входа в систему, у вас также есть возможность связать поставщика OIDC с существующим пользователем с помощью startActivityForLinkWithProvider . Например, вы можете связать нескольких поставщиков с одним и тем же пользователем, позволяя им входить в систему с любым из них.

    Kotlin

    // The user is already signed-in.
    val firebaseUser = firebaseAuth.currentUser!!
    firebaseUser
        .startActivityForLinkWithProvider(activity, provider.build())
        .addOnSuccessListener {
            // Provider credential is linked to the current user.
            // IdP data available in
            // authResult.getAdditionalUserInfo().getProfile().
            // The OAuth access token can also be retrieved:
            // authResult.getCredential().getAccessToken().
            // The OAuth secret can be retrieved by calling:
            // authResult.getCredential().getSecret().
        }
        .addOnFailureListener {
            // Handle failure.
        }

    Java

    // The user is already signed-in.
    FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
    
    firebaseUser
            .startActivityForLinkWithProvider(/* activity= */ this, provider.build())
            .addOnSuccessListener(
                    new OnSuccessListener<AuthResult>() {
                        @Override
                        public void onSuccess(AuthResult authResult) {
                            // Provider credential is linked to the current user.
                            // IdP data available in
                            // authResult.getAdditionalUserInfo().getProfile().
                            // The OAuth access token can also be retrieved:
                            // authResult.getCredential().getAccessToken().
                            // The OAuth secret can be retrieved by calling:
                            // authResult.getCredential().getSecret().
                        }
                    })
            .addOnFailureListener(
                    new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception e) {
                            // Handle failure.
                        }
                    });

  6. Тот же шаблон можно использовать с startActivityForReauthenticateWithProvider , который можно использовать для получения новых учетных данных для конфиденциальных операций, требующих недавнего входа в систему.

    Kotlin

    // The user is already signed-in.
    val firebaseUser = firebaseAuth.currentUser!!
    firebaseUser
        .startActivityForReauthenticateWithProvider(activity, provider.build())
        .addOnSuccessListener {
            // User is re-authenticated with fresh tokens and
            // should be able to perform sensitive operations
            // like account deletion and email or password
            // update.
        }
        .addOnFailureListener {
            // Handle failure.
        }

    Java

    // The user is already signed-in.
    FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
    
    firebaseUser
            .startActivityForReauthenticateWithProvider(/* activity= */ this, provider.build())
            .addOnSuccessListener(
                    new OnSuccessListener<AuthResult>() {
                        @Override
                        public void onSuccess(AuthResult authResult) {
                            // User is re-authenticated with fresh tokens and
                            // should be able to perform sensitive operations
                            // like account deletion and email or password
                            // update.
                        }
                    })
            .addOnFailureListener(
                    new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception e) {
                            // Handle failure.
                        }
                    });

Обработка процесса входа вручную

Если вы уже внедрили процесс входа OpenID Connect в свое приложение, вы можете использовать токен идентификатора напрямую для аутентификации в Firebase:

Kotlin

val providerId = "oidc.example-provider" // As registered in Firebase console.
val credential = oAuthCredential(providerId) {
    setIdToken(idToken) // ID token from OpenID Connect flow.
}
Firebase.auth
    .signInWithCredential(credential)
    .addOnSuccessListener { authResult ->
        // User is signed in.

        // IdP data available in:
        //    authResult.additionalUserInfo.profile
    }
    .addOnFailureListener { e ->
        // Handle failure.
    }

Java

AuthCredential credential = OAuthProvider
        .newCredentialBuilder("oidc.example-provider")  // As registered in Firebase console.
        .setIdToken(idToken)  // ID token from OpenID Connect flow.
        .build();
FirebaseAuth.getInstance()
        .signInWithCredential(credential)
        .addOnSuccessListener(new OnSuccessListener<AuthResult>() {
            @Override
            public void onSuccess(AuthResult authResult) {
                // User is signed in.

                // IdP data available in:
                //    authResult.getAdditionalUserInfo().getProfile()
            }
        })
        .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                // Handle failure.
            }
        });

Следующие шаги

После того, как пользователь входит в систему в первый раз, создается новая учетная запись пользователя, которая связывается с учетными данными (то есть именем пользователя и паролем, номером телефона или информацией поставщика аутентификации), с которыми пользователь вошел в систему. Эта новая учетная запись хранится как часть вашего проекта Firebase и может использоваться для идентификации пользователя в каждом приложении вашего проекта, независимо от того, как пользователь входит в систему.

  • В ваших приложениях вы можете получить базовую информацию профиля пользователя из объекта FirebaseUser . См. Управление пользователями .

  • В правилах безопасности базы данных реального времени и Cloud Storage Firebase Realtime Database вы можете получить уникальный идентификатор пользователя, вошедшего в систему, из переменной auth и использовать его для управления тем, к каким данным пользователь может получить доступ.

Вы можете разрешить пользователям входить в ваше приложение с использованием нескольких поставщиков аутентификации, связав учетные данные поставщика аутентификации с существующей учетной записью пользователя.

Чтобы выйти из системы, вызовите signOut :

Kotlin

Firebase.auth.signOut()

Java

FirebaseAuth.getInstance().signOut();