Аутентификация с использованием OpenID Connect на платформах Apple

Если вы перешли на 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 в свой проект iOS .

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

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

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

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

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

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

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

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

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

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

  1. Добавьте пользовательские схемы URL-адресов в свой проект Xcode:

    1. Откройте конфигурацию проекта: дважды щелкните имя проекта в левом дереве. Выберите свое приложение в разделе «ЦЕЛИ» , затем выберите вкладку «Информация» и разверните раздел «Типы URL-адресов» .
    2. Нажмите кнопку + и добавьте свой идентификатор закодированного приложения в качестве схемы URL-адреса. Вы можете найти свой идентификатор закодированного приложения на странице «Общие настройки» консоли Firebase в разделе вашего приложения для iOS. Остальные поля оставьте пустыми.

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

      Снимок экрана: интерфейс настройки пользовательской схемы URL-адресов Xcode.
  2. Создайте экземпляр OAuthProvider используя идентификатор провайдера, полученный в консоли Firebase.

    var provider = OAuthProvider(providerID: "oidc.example-provider")
    FIROAuthProvider *provider = [FIROAuthProvider providerWithProviderID:@"oidc.example-provider"];
  3. Необязательно : укажите дополнительные пользовательские параметры OAuth, которые вы хотите отправить с запросом OAuth.

    provider.customParameters = [
     
    "login_hint": "user@example.com"
    ]
    [provider setCustomParameters:@{@"login_hint": @"user@example.com"}];

    Узнайте у своего провайдера, какие параметры он поддерживает. Обратите внимание: вы не можете передавать параметры, необходимые для Firebase, с помощью setCustomParameters . Этими параметрами являются client_id , response_type , redirect_uri , state , scope и response_mode .

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

    provider.scopes = ["mail.read", "calendars.read"]
    [provider setScopes:@[@"mail.read", @"calendars.read"]];

    Узнайте у своего провайдера, какие области он поддерживает.

  5. Необязательно : если вы хотите настроить способ представления SFSafariViewController или UIWebView в вашем приложении при отображении reCAPTCHA пользователю, создайте собственный класс, соответствующий протоколу AuthUIDelegate .

  6. Аутентификация в Firebase с использованием объекта провайдера OAuth.

    // If you created a custom class that conforms to AuthUIDelegate,
    // pass it instead of nil:
    provider.getCredentialWith(nil) { credential, error in
     
    if error != nil {
       
    // Handle error.
      }
     
    if credential != nil {
       
    Auth().signIn(with: credential) { authResult, error in
         
    if error != nil {
           
    // Handle error.
          }
         
    // User is signed in.
          // IdP data available in authResult.additionalUserInfo.profile.
          // OAuth access token can also be retrieved:
          // (authResult.credential as? OAuthCredential)?.accessToken
          // OAuth ID token can also be retrieved:
          // (authResult.credential as? OAuthCredential)?.idToken
        }
     
    }
    }
    // If you created a custom class that conforms to AuthUIDelegate,
    // pass it instead of nil:
    [provider getCredentialWithUIDelegate:nil
                                completion
    :^(FIRAuthCredential *_Nullable credential, NSError *_Nullable error) {
     
    if (error) {
       
    // Handle error.
     
    }
     
    if (credential) {
       
    [[FIRAuth auth] signInWithCredential:credential
                                  completion
    :^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
         
    if (error) {
           
    // Handle error.
         
    }
         
    // User is signed in.
         
    // IdP data available in authResult.additionalUserInfo.profile.
         
    // OAuth access token can also be retrieved:
         
    // ((FIROAuthCredential *)authResult.credential).accessToken
         
    // OAuth ID token can also be retrieved:
         
    // ((FIROAuthCredential *)authResult.credential).idToken
       
    }];
     
    }
    }];
  7. Хотя приведенные выше примеры посвящены потокам входа в систему, у вас также есть возможность связать поставщика OIDC с существующим пользователем с помощью linkWithCredential . Например, вы можете связать нескольких поставщиков с одним и тем же пользователем, позволяя им входить в систему с любым из них.

    Auth().currentUser.link(withCredential: credential) { authResult, error in
     
    if error != nil {
       
    // Handle error.
      }
     
    // OIDC credential is linked to the current user.
      // IdP data available in authResult.additionalUserInfo.profile.
      // OAuth access token can also be retrieved:
      // (authResult.credential as? OAuthCredential)?.accessToken
      // OAuth ID token can also be retrieved:
      // (authResult.credential as? OAuthCredential)?.idToken
    }
    [[FIRAuth auth].currentUser
        linkWithCredential
    :credential
                completion
    :^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
     
    if (error) {
       
    // Handle error.
     
    }
     
    // OIDC credential is linked to the current user.
     
    // IdP data available in authResult.additionalUserInfo.profile.
     
    // OAuth access token can also be retrieved:
     
    // ((FIROAuthCredential *)authResult.credential).accessToken
     
    // OAuth ID token can also be retrieved:
     
    // ((FIROAuthCredential *)authResult.credential).idToken
    }];
  8. Тот же шаблон можно использовать с reauthenticateWithCredential , который можно использовать для получения новых учетных данных для конфиденциальных операций, требующих недавнего входа в систему.

    Auth().currentUser.reauthenticateWithCredential(withCredential: credential) { authResult, error in
     
    if error != nil {
       
    // Handle error.
      }
     
    // User is re-authenticated with fresh tokens minted and
      // should be able to perform sensitive operations like account
      // deletion and email or password update.
      // IdP data available in result.additionalUserInfo.profile.
      // Additional OAuth access token can also be retrieved:
      // (authResult.credential as? OAuthCredential)?.accessToken
      // OAuth ID token can also be retrieved:
      // (authResult.credential as? OAuthCredential)?.idToken
    }
    [[FIRAuth auth].currentUser
        reauthenticateWithCredential
    :credential
                          completion
    :^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
     
    if (error) {
       
    // Handle error.
     
    }
     
    // User is re-authenticated with fresh tokens minted and
     
    // should be able to perform sensitive operations like account
     
    // deletion and email or password update.
     
    // IdP data available in result.additionalUserInfo.profile.
     
    // Additional OAuth access token can also be retrieved:
     
    // ((FIROAuthCredential *)authResult.credential).accessToken
     
    // OAuth ID token can also be retrieved:
     
    // ((FIROAuthCredential *)authResult.credential).idToken
    }];

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

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

let credential = OAuthProvider.credential(
    withProviderID
: "oidc.example-provider",  // As registered in Firebase console.
    idToken: idToken,  // ID token from OpenID Connect flow.
    rawNonce: nil
)
Auth.auth().signIn(with: credential) { authResult, error in
   
if error {
       
// Handle error.
        return
   
}
   
// User is signed in.
    // IdP data available in authResult?.additionalUserInfo?.profile
}
FIROAuthCredential *credential =
   
[FIROAuthProvider credentialWithProviderID:@"oidc.example-provider"  // As registered in Firebase console.
                                       
IDToken:idToken  // ID token from OpenID Connect flow.
                                      rawNonce
:nil];
[[FIRAuth auth] signInWithCredential:credential
                          completion
:^(FIRAuthDataResult * _Nullable authResult,
                                     
NSError * _Nullable error) {
   
if (error != nil) {
       
// Handle error.
       
return;
   
}
   
// User is signed in.
   
// IdP data available in authResult.additionalUserInfo.profile
}];

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

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

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

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

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

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

let firebaseAuth = Auth.auth()
do {
 
try firebaseAuth.signOut()
} catch let signOutError as NSError {
 
print("Error signing out: %@", signOutError)
}
NSError *signOutError;
BOOL status
= [[FIRAuth auth] signOut:&signOutError];
if (!status) {
 
NSLog(@"Error signing out: %@", signOutError);
 
return;
}

Вы также можете добавить код обработки ошибок для всего спектра ошибок аутентификации. См. Обработка ошибок .