Firebase 提供多項功能,可讓你完全掌控驗證
使用安全的 JSON Web Token (JWT) 驗證使用者或裝置。您產生
這些權杖傳回用戶端裝置,
透過 signInWithCustomToken()
方法進行驗證。
為此,您必須建立接受登入的伺服器端點
憑證,例如使用者名稱和密碼
,則會傳回自訂 JWT。接著,從伺服器傳回的自訂 JWT 就能
用戶端裝置會使用這個金鑰向 Firebase 進行驗證
(iOS+、Android、
網頁)。驗證完畢後,這個身分就會
存取其他 Firebase 服務 (例如 Firebase Realtime Database) 時使用的
和 Cloud Storage。此外,JWT 的內容
可在應用程式的 auth
物件中使用
Realtime Database Security Rules 和
request.auth
物件
Cloud Storage Security Rules。
您可以使用 Firebase Admin SDK 建立自訂權杖,或者也可以 使用第三方 JWT 程式庫 (如果您的伺服器是以 也就是 Firebase 不支援的語言
事前準備
自訂權杖是已簽署的 JWT,且用來簽署的私密金鑰所屬的金鑰為該 JWT Google 服務帳戶您可以透過多種方式指定 Google 服務 Firebase Admin SDK 應用來簽署自訂的帳戶 符記:
- 使用服務帳戶 JSON 檔案 -- 這個方法適用於任何 但是您需要封裝服務帳戶 JSON 檔案 和程式碼必須特別小心,確保 服務帳戶 JSON 檔案未對外公開。
- 讓 Admin SDK 找到服務帳戶 -- 這個方法 可用於 Google 代管的環境,如 Google Cloud 函式和 App Engine。您可能需要設定一些 以Google Cloud控制台授予其他權限
- 使用服務帳戶 ID -- 在 Google 代管的環境中使用時,此方法會使用 指定服務帳戶的金鑰 不過,它會使用遠端網路服務,並可能必須 可透過 Google Cloud 控制台。
使用服務帳戶 JSON 檔案
服務帳戶 JSON 檔案內含與服務相關的所有資訊 帳戶 (包括 RSA 私密金鑰)。您可以前往 Firebase 控制台。按照 Admin SDK 設定 操作說明,進一步瞭解如何 使用服務帳戶 JSON 檔案初始化 Admin SDK。
這種初始化方法適用於各種 Admin SDK Deployment 規格這麼做也能讓 Admin SDK 建立及簽署自訂權杖 無需進行任何遠端 API 呼叫 您需要封裝服務帳戶 JSON 檔案 和程式碼另請注意,服務帳戶中的私密金鑰 JSON 檔案是機密資訊,請特別留意以保留 機密資料。具體而言,請勿新增服務帳戶 JSON 檔案 公開版本管控
讓 Admin SDK 探索服務帳戶
如果您的程式碼部署於 Google 代管的環境,Admin SDK 可以嘗試自動發現簽署自訂權杖的方法:
如果您的程式碼是部署在 App Engine 標準環境中, Java、Python 或 Go,Admin SDK 都可以使用 應用程式身分識別服務 以簽署自訂權杖應用程式身分識別服務 透過 Google App 為您的應用程式佈建的服務帳戶簽署資料 Compute Engine
如果您的程式碼是部署在其他代管環境 (例如 Google Cloud) 函式、Google Compute Engine),Firebase Admin SDK 可以自動探索 來自本機的服務帳戶 ID 字串 中繼資料伺服器。 找到的服務帳戶 ID 會搭配 IAM 使用 遠端簽署權杖
如要使用這些簽署方法,請透過 Google 應用程式預設憑證,而且未指定服務帳戶 ID 字串:
Node.js
initializeApp();
Java
FirebaseApp.initializeApp();
Python
default_app = firebase_admin.initialize_app()
Go
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
環境變數指向該變數。
如果 Firebase Admin SDK 必須找到服務帳戶 ID 字串,就會 因此您的程式碼第一次建立自訂符記時 系統會快取結果,並在後續的權杖簽署作業中重複使用。 自動發現的服務帳戶 ID 通常是預設服務之一 帳戶:Google Cloud
自動探索服務和明確指定的服務帳戶 ID 一樣
帳戶 ID 必須具備以下項目的iam.serviceAccounts.signBlob
權限:
才能正常運作您可能需要使用
IAM 與管理員專區
Google Cloud控制台中以授權給預設服務帳戶
授予必要權限。詳情請參閱下方的疑難排解一節。
使用服務帳戶 ID
如要維持應用程式各部分之間的一致性,您可以 指定要在執行期間用於簽署權杖的服務帳戶 ID 部署容器 這可讓 IAM 政策更簡單、安全,且不必 在程式碼中加入服務帳戶 JSON 檔案
您可以在
Google Cloud 控制台,
或下載服務帳戶 JSON 檔案的 client_email
欄位中。
服務帳戶 ID 是採用下列格式的電子郵件地址:
<client-id>@<project-id>.iam.gserviceaccount.com
。可明確識別
或 Google Cloud 專案的服務帳戶。
如要使用獨立的服務帳戶 ID 建立自訂權杖,請初始化 SDK 如下所示:
Node.js
initializeApp({
serviceAccountId: 'my-client-id@my-project-id.iam.gserviceaccount.com',
});
Java
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)
Go
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",
});
服務帳戶 ID 不是機密資訊,因此會遭到外洩
依序進行但為了透過指定的服務簽署自訂權杖
帳戶,Firebase Admin SDK 必須叫用遠端服務。
此外,您也必須確定 Admin SDK 所在的服務帳戶
用於撥打這通電話
—通常為 {project-name}@appspot.gserviceaccount.com
—
擁有iam.serviceAccounts.signBlob
權限。
詳情請參閱下方的疑難排解一節。
使用 Firebase Admin SDK 建立自訂權杖
Firebase Admin SDK 內建可建立自訂權杖的方法。在
最少,您必須提供 uid
,可以是任何字串,但應該是
明確識別您要驗證的使用者或裝置。這些權杖有效期限
一小時後
Node.js
const uid = 'some-uid';
getAuth()
.createCustomToken(uid)
.then((customToken) => {
// Send token back to client
})
.catch((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)
C#
var uid = "some-uid";
string customToken = await FirebaseAuth.DefaultInstance.CreateCustomTokenAsync(uid);
// Send token back to client
您也可以選擇指定要納入自訂標籤的其他著作權聲明
產生下一個符記舉例來說,下方範例新增了 premiumAccount
欄位
自訂權杖,您可以在 auth
/ request.auth
物件中找到
在您的安全性規則中執行以下操作:
Node.js
const userId = 'some-uid';
const additionalClaims = {
premiumAccount: true,
};
getAuth()
.createCustomToken(userId, additionalClaims)
.then((customToken) => {
// Send token back to client
})
.catch((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)
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+
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.AuthResult result = task.Result;
Debug.LogFormat("User signed in successfully: {0} ({1})",
result.User.DisplayName, result.User.UserId);
});
C++
firebase::Future<firebase::auth::AuthResult> result =
auth->SignInWithCustomToken(custom_token);
Web
firebase.auth().signInWithCustomToken(token)
.then((userCredential) => {
// Signed in
var user = userCredential.user;
// ...
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
Web
import { getAuth, signInWithCustomToken } from "firebase/auth";
const auth = getAuth();
signInWithCustomToken(auth, token)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
// ...
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
// ...
});
如果驗證成功,您的使用者現在會登入
用戶端應用程式,使用 uid
指定的帳戶,自訂用戶端應用程式
產生下一個符記如果該帳戶先前並不存在,使用者的記錄就會
已建立。
與其他登入方式相同 (例如
signInWithEmailAndPassword()
和 signInWithCredential()
) auth
物件
位於Realtime Database Security Rules和
中的 request.auth
物件
Cloud Storage Security Rules 將成為
已填入使用者的 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 管理員 SDK,您還是可以手動建立自訂符記。首先 為您的語言尋找第三方 JWT 程式庫。接著,請使用 用於建立 JWT,其中包含下列憑證附加資訊:
自訂權杖憑證附加資訊 | ||
---|---|---|
alg |
演算法 | "RS256" |
iss |
核發單位 | 專案的服務帳戶電子郵件地址 |
sub |
主旨 | 專案的服務帳戶電子郵件地址 |
aud |
目標對象 | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat |
核發時間 | 目前時間 (從 UNIX 紀元起算,以秒為單位) |
exp |
到期時間 |
權杖到期時間 (從 UNIX 紀元起算,以秒為單位)。這項服務
可以是晚於 iat 的 3,600 秒。
注意:這只會控制自訂權杖本身的時間 過期。但您一旦透過 signInWithCustomToken() ,孩子會在以下位置的登入狀態保持登入:
直到工作階段失效或使用者登出為止。
|
uid |
已登入使用者的專屬 ID 必須是字串,位於
長度介於 1 到 128 個字元之間 (含首尾)。較短的 uid ,帶來更好的產品
才需進行
|
|
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
建立自訂權杖後,請將權杖傳送至用戶端應用程式, 進行驗證操作方法請參閱上方的程式碼範例。
疑難排解
本節將概述開發人員在 以及解析方式
未啟用 IAM API
如果您為簽署權杖指定服務帳戶 ID 顯示類似下列內容的錯誤:
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.
Firebase Admin SDK 會使用 IAM API 簽署符記這個錯誤表示 IAM API 目前未啟用 適用於 Firebase 專案。在網路瀏覽器中開啟錯誤訊息中的連結,然後 按一下 [啟用 API]按鈕,為專案啟用該 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
:
- 開啟 IAM 與管理員 頁面Google Cloud。
- 選取您的專案並點選 [繼續]。
- 按一下與您要更新的服務帳戶對應的編輯圖示。
- 按一下 [新增其他角色]。
- 輸入「Service Account Token Creator」進入搜尋篩選器,然後選取 從結果中找出這個新點
- 按一下 [儲存]以確認授予角色
請參閱 IAM 說明文件 進一步瞭解這項程序,或瞭解如何 gcloud 指令列工具建立 Docker 映像檔。
無法判斷服務帳戶
如果收到類似下列內容的錯誤訊息,表示 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 自動探索服務帳戶 ID,請確認 且該程式碼會部署在含有中繼資料伺服器的代管 Google 環境中。 否則,請務必指定服務帳戶 JSON 檔案或服務帳戶 ID 與 SDK 初始化的一致