创建自定义令牌

Firebase 允许使用安全的 JSON Web 令牌 (JWT) 对用户或设备进行身份验证,让您可以完全控制身份验证。您可以在自己的服务器上生成这些令牌,并将它们传递回客户端设备,然后通过 signInWithCustomToken() 方法使用这些令牌进行身份验证。

为了实现上述目标,您必须创建一个接受登录凭据(如用户名和密码)并在凭据有效时返回自定义 JWT 的服务器端点。然后,客户端设备即可使用从您的服务器返回的这个自定义 JWT 进行 Firebase 身份验证(iOSAndroid网页)。通过验证的身份会被用于访问其他 Firebase 服务(如 Firebase 实时数据库和 Cloud Storage)。此外,您的 Firebase 实时数据库安全规则中的 auth 对象和 Cloud Storage 安全规则中的 request.auth 对象都会包含 JWT 的内容。

您可以使用 Firebase Admin SDK 创建自定义令牌;或者,如果您的服务器是使用非 Firebase 原生支持的语言编写的,您可以使用第三方 JWT 库进行创建。

开始前的准备工作

要使用 Firebase Admin SDK 创建自定义令牌,您必须要有服务帐号。请参阅 Admin SDK 设置说明,详细了解如何使用服务帐号初始化 Admin SDK。

使用 Firebase Admin SDK 创建自定义令牌

Firebase Admin SDK 内置了创建自定义令牌的方法。您至少需要提供一个 uid - 它可以是任何可唯一标识要进行身份验证的用户或设备的字符串。这些令牌会在 1 小时后过期。

Node.js

var 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);
  });

Java

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)

Go

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)

您还可以选择性地指定在自定义令牌中包含附加声明。以下示例的自定义令牌中添加了 premiumAccount 字段,该字段将会出现在您的安全规则中的 auth / request.auth 对象中:

Node.js

var uid = "some-uid";
var additionalClaims = {
  premiumAccount: true
};

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

Java

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)

Go

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)

在客户端上使用自定义令牌登录

在创建自定义令牌之后,您应该将其发送至客户端应用。该客户端应用将通过调用 signInWithCustomToken() 用此自定义令牌进行身份验证:

iOS

Objective-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);
                }
            }
        });

Unity

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())时一样,您的 Firebase 实时数据库安全规则中的 auth 对象和 Cloud Storage 安全规则中的 request.auth 对象中将填充用户的 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.uid == "some-uid";
    }
  }
}

如果自定义令牌包含额外的声明,您可以从规则中的 auth.token(Firebase 实时数据库)或 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 计时原点之间相隔的秒数),该时间可以比 iat 晚最多 3600 秒
注意:这仅会控制自定义令牌本身的过期时间。但是,一旦您使用 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

使用 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 进行身份验证。您可以参阅上方的示例代码,了解如何实现这一点。

发送以下问题的反馈:

此网页
需要帮助?请访问我们的支持页面