Google is committed to advancing racial equity for Black communities. See how.
Эта страница была переведа с помощью Cloud Translation API.
Switch to English

Создать собственные токены

Firebase дает вам полный контроль над аутентификацией, позволяя аутентифицировать пользователей или устройства с помощью безопасных веб-токенов JSON (JWT). Вы генерируете эти токены на своем сервере, передаете их обратно на клиентское устройство, а затем используете их для аутентификации с помощью signInWithCustomToken() .

Для этого необходимо создать конечную точку сервера, которая принимает учетные данные для входа, такие как имя пользователя и пароль, и, если учетные данные действительны, возвращает пользовательский JWT. Пользовательский JWT, возвращенный с вашего сервера, может затем использоваться клиентским устройством для аутентификации с помощью Firebase ( iOS , Android , Интернет ). После аутентификации этот идентификатор будет использоваться при доступе к другим сервисам Firebase, таким как база данных Firebase Realtime и облачное хранилище. Кроме того, содержимое JWT будет доступно в объекте auth в ваших правилах безопасности базы данных Firebase Realtime и в объекте request.auth в ваших правилах безопасности облачного хранилища .

Вы можете создать собственный токен с помощью Firebase Admin SDK или использовать стороннюю библиотеку JWT, если ваш сервер написан на языке, который Firebase изначально не поддерживает.

Прежде чем вы начнете

Пользовательские токены - это подписанные JWT, где закрытый ключ, используемый для подписи, принадлежит учетной записи службы Google. Существует несколько способов указать учетную запись службы Google, которую должен использовать Firebase Admin SDK для подписи пользовательских токенов:

  • Использование файла JSON учетной записи службы - этот метод можно использовать в любой среде, но для этого необходимо упаковать файл JSON учетной записи службы вместе с кодом. Особое внимание следует уделить тому, чтобы файл JSON учетной записи службы не был открыт для внешних сторон.
  • Разрешение Admin SDK обнаруживать учетную запись службы - этот метод можно использовать в средах, управляемых Google, таких как Google Cloud Functions и Google App Engine. Возможно, вам придется настроить некоторые дополнительные разрешения через консоль Google Cloud Platform.
  • Использование идентификатора учетной записи службы - при использовании в среде, управляемой Google, этот метод будет подписывать токены с использованием ключа указанной учетной записи службы. Однако он использует удаленную веб-службу, и вам может потребоваться настроить дополнительные разрешения для этой учетной записи службы через консоль Google Cloud Platform.

Использование JSON-файла служебного аккаунта

Файлы JSON сервисного аккаунта содержат всю информацию, соответствующую сервисным аккаунтам (включая закрытый ключ RSA). Их можно загрузить из консоли Firebase. Следуйте инструкциям по настройке Admin SDK для получения дополнительной информации о том, как инициализировать Admin SDK с помощью файла JSON учетной записи службы.

Этот метод инициализации подходит для широкого спектра развертываний Admin SDK. Также он позволяет Admin SDK создавать и подписывать пользовательские токены локально, без каких-либо удаленных вызовов API. Главный недостаток этого подхода заключается в том, что он требует, чтобы вы упаковали JSON-файл учетной записи службы вместе с кодом. Также обратите внимание, что закрытый ключ в файле JSON служебной учетной записи является конфиденциальной информацией, и необходимо соблюдать особую осторожность, чтобы сохранить ее конфиденциальность. В частности, воздержитесь от добавления файлов JSON сервисного аккаунта в общедоступный контроль версий.

Разрешение Admin SDK обнаруживать учетную запись службы

Если ваш код развернут в среде, управляемой Google, Admin SDK может попытаться автоматически обнаружить способ подписи пользовательских токенов:

  • Если ваш код развернут в стандартной среде Google App Engine для Java, Python или Go, Admin SDK может использовать службу App Identity, присутствующую в этой среде, для подписи пользовательских токенов. Служба App Identity подписывает данные с помощью учетной записи службы, предоставленной для вашего приложения с помощью Google App Engine.

  • Если ваш код развернут в какой-либо другой управляемой среде (например, Google Cloud Functions, Google Compute Engine), Firebase Admin SDK может автоматически обнаруживать строку идентификатора учетной записи службы с локального сервера метаданных . Обнаруженный идентификатор учетной записи службы затем используется вместе со службой IAM для удаленной подписи токенов.

Чтобы использовать эти методы подписи, инициализируйте SDK с учетными данными приложения Google по умолчанию и не указывайте строку идентификатора учетной записи службы:

Node.js

admin.initializeApp();

Джава

FirebaseApp.initializeApp();

Python

default_app = firebase_admin.initialize_app()

Идти

app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
	log.Fatalf("error initializing app: %v\n", err)
}

C #

FirebaseApp.Create();

Чтобы протестировать тот же код локально, загрузите файл JSON учетной записи службы и установите GOOGLE_APPLICATION_CREDENTIALS среды GOOGLE_APPLICATION_CREDENTIALS указывающую на него.

Если Firebase Admin SDK должен обнаружить строку идентификатора учетной записи службы, он делает это, когда ваш код впервые создает пользовательский токен. Результат кэшируется и повторно используется для последующих операций подписания токена. Идентификатор автоматически обнаруживаемой учетной записи службы обычно является одной из учетных записей службы по умолчанию, предоставляемых Google Cloud Platform:

Как и в случае с явно указанными идентификаторами учетных записей служб, идентификаторы автоматически обнаруженных учетных записей служб должны иметь разрешение iam.serviceAccounts.signBlob для работы создания пользовательского токена. Возможно, вам придется использовать раздел IAM и администратора консоли Google Cloud Platform, чтобы предоставить учетным записям служб по умолчанию необходимые разрешения. Более подробную информацию см. В разделе устранения неполадок ниже.

Использование идентификатора сервисного аккаунта

Чтобы поддерживать согласованность между различными частями вашего приложения, вы можете указать идентификатор учетной записи службы, ключи которой будут использоваться для подписи токенов при работе в среде, управляемой Google. Это может сделать политики IAM более простыми и безопасными и избежать необходимости включать JSON-файл служебной учетной записи в ваш код.

Идентификатор учетной записи службы можно найти в консоли Google Cloud Platform или в поле client_email загруженного файла JSON учетной записи службы. Идентификаторы сервисных аккаунтов - это адреса электронной почты в следующем формате: <client-id>@<project-id>.iam.gserviceaccount.com . Они однозначно идентифицируют сервисные аккаунты в проектах Firebase и Google Cloud Platform.

Чтобы создать собственные токены с использованием отдельного идентификатора учетной записи службы, инициализируйте SDK, как показано ниже:

Node.js

admin.initializeApp({
  serviceAccountId: 'my-client-id@my-project-id.iam.gserviceaccount.com',
});

Джава

FirebaseOptions options = FirebaseOptions.builder()
    .setCredentials(GoogleCredentials.getApplicationDefault())
    .setServiceAccountId("my-client-id@my-project-id.iam.gserviceaccount.com")
    .build();
FirebaseApp.initializeApp(options);

Python

options = {
    'serviceAccountId': 'my-client-id@my-project-id.iam.gserviceaccount.com',
}
firebase_admin.initialize_app(options=options)

Идти

conf := &firebase.Config{
	ServiceAccountID: "my-client-id@my-project-id.iam.gserviceaccount.com",
}
app, err := firebase.NewApp(context.Background(), conf)
if err != nil {
	log.Fatalf("error initializing app: %v\n", err)
}

C #

FirebaseApp.Create(new AppOptions()
{
    Credential = GoogleCredential.GetApplicationDefault(),
    ServiceAccountId = "my-client-id@my-project-id.iam.gserviceaccount.com",
});

Идентификаторы сервисных аккаунтов не являются конфиденциальной информацией, поэтому их раскрытие несущественно. Однако для подписания пользовательских токенов с указанной учетной записью службы Firebase Admin SDK должен вызывать удаленную службу. Более того, вы также должны убедиться, что служебный аккаунт, который Admin SDK использует для выполнения этого вызова - обычно {project-name}@appspot.gserviceaccount.com - имеет разрешение iam.serviceAccounts.signBlob . Более подробную информацию см. В разделе устранения неполадок ниже.

Создание собственных токенов с помощью Firebase Admin SDK

В Firebase Admin SDK есть встроенный метод для создания пользовательских токенов. Как минимум, вам необходимо предоставить uid , который может быть любой строкой, но должен однозначно идентифицировать пользователя или устройство, которое вы аутентифицируете. Срок действия этих токенов истекает через час.

Node.js

let uid = 'some-uid';

admin.auth().createCustomToken(uid)
  .then(function(customToken) {
    // Send token back to client
  })
  .catch(function(error) {
    console.log('Error creating custom token:', error);
  });

Джава

String uid = "some-uid";

String customToken = FirebaseAuth.getInstance().createCustomToken(uid);
// Send token back to client

Python

uid = 'some-uid'

custom_token = auth.create_custom_token(uid)

Идти

client, err := app.Auth(context.Background())
if err != nil {
	log.Fatalf("error getting Auth client: %v\n", err)
}

token, err := client.CustomToken(ctx, "some-uid")
if err != nil {
	log.Fatalf("error minting custom token: %v\n", err)
}

log.Printf("Got custom token: %v\n", token)

C #

var uid = "some-uid";

string customToken = await FirebaseAuth.DefaultInstance.CreateCustomTokenAsync(uid);
// Send token back to client

Вы также можете дополнительно указать дополнительные утверждения, которые будут включены в настраиваемый токен. Например, ниже к настраиваемому токену добавлено поле premiumAccount , которое будет доступно в объектах auth / request.auth в ваших Правилах безопасности:

Node.js

let userId = 'some-uid';
let additionalClaims = {
  premiumAccount: true
};

admin.auth().createCustomToken(userId, additionalClaims)
  .then(function(customToken) {
    // Send token back to client
  })
  .catch(function(error) {
    console.log('Error creating custom token:', error);
  });

Джава

String uid = "some-uid";
Map<String, Object> additionalClaims = new HashMap<String, Object>();
additionalClaims.put("premiumAccount", true);

String customToken = FirebaseAuth.getInstance()
    .createCustomToken(uid, additionalClaims);
// Send token back to client

Python

uid = 'some-uid'
additional_claims = {
    'premiumAccount': True
}

custom_token = auth.create_custom_token(uid, additional_claims)

Идти

client, err := app.Auth(context.Background())
if err != nil {
	log.Fatalf("error getting Auth client: %v\n", err)
}

claims := map[string]interface{}{
	"premiumAccount": true,
}

token, err := client.CustomTokenWithClaims(ctx, "some-uid", claims)
if err != nil {
	log.Fatalf("error minting custom token: %v\n", err)
}

log.Printf("Got custom token: %v\n", token)

C #

var uid = "some-uid";
var additionalClaims = new Dictionary<string, object>()
{
    { "premiumAccount", true },
};

string customToken = await FirebaseAuth.DefaultInstance
    .CreateCustomTokenAsync(uid, additionalClaims);
// Send token back to client

Войдите в систему с помощью пользовательских токенов на клиентах

После создания пользовательского токена необходимо отправить его в клиентское приложение. Клиентское приложение аутентифицируется с помощью специального токена, вызывая signInWithCustomToken() :

iOS

Цель-C
[[FIRAuth auth] signInWithCustomToken:customToken
                           completion:^(FIRAuthDataResult * _Nullable authResult,
                                        NSError * _Nullable error) {
  // ...
}];
Swift
Auth.auth().signIn(withCustomToken: customToken ?? "") { (user, error) in
  // ...
}

Android

mAuth.signInWithCustomToken(mCustomToken)
        .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                    // Sign in success, update UI with the signed-in user's information
                    Log.d(TAG, "signInWithCustomToken:success");
                    FirebaseUser user = mAuth.getCurrentUser();
                    updateUI(user);
                } else {
                    // If sign in fails, display a message to the user.
                    Log.w(TAG, "signInWithCustomToken:failure", task.getException());
                    Toast.makeText(CustomAuthActivity.this, "Authentication failed.",
                            Toast.LENGTH_SHORT).show();
                    updateUI(null);
                }
            }
        });

Единство

auth.SignInWithCustomTokenAsync(custom_token).ContinueWith(task => {
  if (task.IsCanceled) {
    Debug.LogError("SignInWithCustomTokenAsync was canceled.");
    return;
  }
  if (task.IsFaulted) {
    Debug.LogError("SignInWithCustomTokenAsync encountered an error: " + task.Exception);
    return;
  }

  Firebase.Auth.FirebaseUser newUser = task.Result;
  Debug.LogFormat("User signed in successfully: {0} ({1})",
      newUser.DisplayName, newUser.UserId);
});

C ++

firebase::Future<firebase::auth::User*> result =
    auth->SignInWithCustomToken(custom_token);

Интернет

firebase.auth().signInWithCustomToken(token).catch(function(error) {
  // Handle Errors here.
  var errorCode = error.code;
  var errorMessage = error.message;
  // ...
});

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

Так же, как и с другими методами входа (такими как signInWithEmailAndPassword() и signInWithCredential() ), объект auth в ваших правилах безопасности базы данных Firebase Realtime и объект request.auth в ваших правилах безопасности облачного хранилища будут заполнены signInWithCredential() пользователя. uid . В этом случае uid будет тем, который вы указали при генерации пользовательского токена.

Правила базы данных

{
  "rules": {
    "adminContent": {
      ".read": "auth.uid === 'some-uid'"
    }
  }
}

Правила хранения

service firebase.storage {
  match /b/<your-firebase-storage-bucket>/o {
    match /adminContent/{filename} {
      allow read, write: if request.auth != null && request.auth.uid == "some-uid";
    }
  }
}

Если пользовательский токен содержит дополнительные утверждения, на них можно ссылаться с помощью auth.token (Firebase Realtime Database) или request.auth.token (Cloud Storage) в ваших правилах:

Правила базы данных

{
  "rules": {
    "premiumContent": {
      ".read": "auth.token.premiumAccount === true"
    }
  }
}

Правила хранения

service firebase.storage {
  match /b/<your-firebase-storage-bucket>/o {
    match /premiumContent/{filename} {
      allow read, write: if request.auth.token.premiumAccount == true;
    }
  }
}

Создавайте собственные токены с помощью сторонней библиотеки JWT

Если ваш бэкэнд работает на языке, на котором нет официального Firebase Admin SDK, вы все равно можете вручную создавать собственные токены. Сначала найдите стороннюю библиотеку JWT для вашего языка. Затем используйте эту библиотеку JWT для создания JWT, который включает следующие утверждения:

Пользовательские заявки на токены
alg Алгоритм "RS256"
iss Эмитент Адрес электронной почты сервисного аккаунта вашего проекта
sub Предмет Адрес электронной почты сервисного аккаунта вашего проекта
aud Зрительская аудитория "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat Выпущено вовремя Текущее время в секундах с эпохи UNIX.
exp Время окончания срока действия Время в секундах с эпохи UNIX, когда истекает срок действия токена. Это может быть максимум на 3600 секунд позже, чем iat .
Примечание: это контролирует только время, когда истекает срок действия самого пользовательского токена . Но после того, как вы signInWithCustomToken() в систему с помощью signInWithCustomToken() , они будут оставаться в системе до тех пор, пока их сеанс не будет аннулирован или пользователь не выйдет из системы.
uid Уникальный идентификатор вошедшего в систему пользователя должен быть строкой длиной от 1 до 36 символов.
claims (необязательно) Необязательные настраиваемые утверждения для включения в переменные auth / request.auth правил безопасности

Вот несколько примеров реализации того, как создавать собственные токены на разных языках, которые Firebase Admin SDK не поддерживает:

PHP

Используя php-jwt :

// Requires: composer require firebase/php-jwt
use Firebase\JWT\JWT;

// Get your service account's email address and private key from the JSON key file
$service_account_email = "abc-123@a-b-c-123.iam.gserviceaccount.com";
$private_key = "-----BEGIN PRIVATE KEY-----...";

function create_custom_token($uid, $is_premium_account) {
  global $service_account_email, $private_key;

  $now_seconds = time();
  $payload = array(
    "iss" => $service_account_email,
    "sub" => $service_account_email,
    "aud" => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
    "iat" => $now_seconds,
    "exp" => $now_seconds+(60*60),  // Maximum expiration time is one hour
    "uid" => $uid,
    "claims" => array(
      "premium_account" => $is_premium_account
    )
  );
  return JWT::encode($payload, $private_key, "RS256");
}

Рубин

Использование ruby-jwt :

require "jwt"

# Get your service account's email address and private key from the JSON key file
$service_account_email = "service-account@my-project-abc123.iam.gserviceaccount.com"
$private_key = OpenSSL::PKey::RSA.new "-----BEGIN PRIVATE KEY-----\n..."

def create_custom_token(uid, is_premium_account)
  now_seconds = Time.now.to_i
  payload = {:iss => $service_account_email,
             :sub => $service_account_email,
             :aud => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
             :iat => now_seconds,
             :exp => now_seconds+(60*60), # Maximum expiration time is one hour
             :uid => uid,
             :claims => {:premium_account => is_premium_account}}
  JWT.encode payload, $private_key, "RS256"
end

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

Исправление проблем

В этом разделе описаны некоторые общие проблемы, с которыми могут столкнуться разработчики при создании пользовательских токенов, и способы их решения.

IAM API не включен

Если вы указываете идентификатор учетной записи службы для подписи токенов, вы можете получить ошибку, подобную следующей:

Identity and Access Management (IAM) API has not been used in project
1234567890 before or it is disabled. Enable it by visiting
https://console.developers.google.com/apis/api/iam.googleapis.com/overview?project=1234567890
then retry. If you enabled this API recently, wait a few minutes for the action
to propagate to our systems and retry.

SDK Firebase Admin использует IAM API для подписи токенов. Эта ошибка указывает на то, что IAM API в настоящее время не включен для вашего проекта Firebase. Откройте ссылку в сообщении об ошибке в веб-браузере и нажмите кнопку «Включить API», чтобы включить его для вашего проекта.

У служебного аккаунта нет необходимых разрешений

Если учетная запись службы Firebase Admin SDK не имеет разрешения iam.serviceAccounts.signBlob , вы можете получить следующее сообщение об ошибке:

Permission iam.serviceAccounts.signBlob is required to perform this operation
on service account projects/-/serviceAccounts/{your-service-account-id}.

Самый простой способ решить эту проблему - предоставить роль IAM «Создатель токена сервисного аккаунта» соответствующему сервисному аккаунту, обычно {project-name}@appspot.gserviceaccount.com :

  1. Откройте страницу IAM и администратора в консоли Google Cloud Platform.
  2. Выберите свой проект и нажмите «Продолжить».
  3. Щелкните значок редактирования, соответствующий учетной записи службы, которую вы хотите обновить.
  4. Щелкните «Добавить другую роль».
  5. Введите «Создатель токена учетной записи службы» в фильтр поиска и выберите его из результатов.
  6. Нажмите «Сохранить», чтобы подтвердить предоставление роли.

Обратитесь к документации IAM для получения дополнительных сведений об этом процессе или узнайте, как выполнять обновления ролей с помощью инструментов командной строки gcloud.

Не удалось определить сервисный аккаунт

Если вы получаете сообщение об ошибке, подобное приведенному ниже, значит, Firebase Admin SDK не был должным образом инициализирован.

Failed to determine service account ID. Initialize the SDK with service account
credentials or specify a service account ID with iam.serviceAccounts.signBlob
permission.

Если вы полагаетесь на SDK для автоматического определения идентификатора учетной записи службы, убедитесь, что код развернут в управляемой среде Google с сервером метаданных. В противном случае не забудьте указать файл JSON учетной записи службы или идентификатор учетной записи службы при инициализации SDK.