如果您的 Firebase 客户端应用与自定义后端服务器通信,您可能需要识别该服务器上当前登录的用户。要安全地执行此操作,请在成功登录后,使用 HTTPS 将用户的 ID 令牌发送到您的服务器。然后,在服务器上,验证 ID 令牌的完整性和真实性并从中检索uid
。您可以使用以这种方式传输的uid
来安全地识别您服务器上当前登录的用户。
在你开始之前
要使用 Firebase Admin SDK 验证 ID 令牌,您必须拥有一个服务帐号。请按照Admin SDK 设置说明获取有关如何使用服务帐户初始化 Admin SDK 的更多信息。
检索客户端上的 ID 令牌
当用户或设备成功登录时,Firebase 会创建一个相应的 ID 令牌来唯一标识他们并授予他们访问多个资源的权限,例如 Firebase 实时数据库和云存储。您可以重复使用该 ID 令牌来识别自定义后端服务器上的用户或设备。要从客户端检索 ID 令牌,请确保用户已登录,然后从已登录用户处获取 ID 令牌:
iOS+
Objective-C
FIRUser *currentUser = [FIRAuth auth].currentUser;
[currentUser getIDTokenForcingRefresh:YES
completion:^(NSString *_Nullable idToken,
NSError *_Nullable error) {
if (error) {
// Handle error
return;
}
// Send token to your backend via HTTPS
// ...
}];
迅速
let currentUser = FIRAuth.auth()?.currentUser
currentUser?.getIDTokenForcingRefresh(true) { idToken, error in
if let error = error {
// Handle error
return;
}
// Send token to your backend via HTTPS
// ...
}
安卓
FirebaseUser mUser = FirebaseAuth.getInstance().getCurrentUser();
mUser.getIdToken(true)
.addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
public void onComplete(@NonNull Task<GetTokenResult> task) {
if (task.isSuccessful()) {
String idToken = task.getResult().getToken();
// Send token to your backend via HTTPS
// ...
} else {
// Handle error -> task.getException();
}
}
});
统一
Firebase.Auth.FirebaseUser user = auth.CurrentUser;
user.TokenAsync(true).ContinueWith(task => {
if (task.IsCanceled) {
Debug.LogError("TokenAsync was canceled.");
return;
}
if (task.IsFaulted) {
Debug.LogError("TokenAsync encountered an error: " + task.Exception);
return;
}
string idToken = task.Result;
// Send token to your backend via HTTPS
// ...
});
C++
firebase::auth::User* user = auth->current_user();
if (user != nullptr) {
firebase::Future<std::string> idToken = user->GetToken(true);
// Send token to your backend via HTTPS
// ...
}
网络
firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {
// Send token to your backend via HTTPS
// ...
}).catch(function(error) {
// Handle error
});
获得 ID 令牌后,您可以将该 JWT 发送到您的后端并使用 Firebase Admin SDK 验证它,或者如果您的服务器是用 Firebase 本身不支持的语言编写的,则可以使用第三方 JWT 库。
使用 Firebase Admin SDK 验证 ID 令牌
Firebase Admin SDK 具有用于验证和解码 ID 令牌的内置方法。如果提供的 ID 令牌具有正确的格式、未过期且已正确签名,则该方法返回解码后的 ID 令牌。您可以从解码的令牌中获取用户或设备的uid
。
按照Admin SDK 设置说明使用服务帐户初始化 Admin SDK。然后,使用verifyIdToken()
方法验证 ID 令牌:
节点.js
// idToken comes from the client app
getAuth()
.verifyIdToken(idToken)
.then((decodedToken) => {
const uid = decodedToken.uid;
// ...
})
.catch((error) => {
// Handle error
});
爪哇
// idToken comes from the client app (shown above)
FirebaseToken decodedToken = FirebaseAuth.getInstance().verifyIdToken(idToken);
String uid = decodedToken.getUid();
Python
# id_token comes from the client app (shown above)
decoded_token = auth.verify_id_token(id_token)
uid = decoded_token['uid']
去
client, err := app.Auth(ctx)
if err != nil {
log.Fatalf("error getting Auth client: %v\n", err)
}
token, err := client.VerifyIDToken(ctx, idToken)
if err != nil {
log.Fatalf("error verifying ID token: %v\n", err)
}
log.Printf("Verified ID token: %v\n", token)
C#
FirebaseToken decodedToken = await FirebaseAuth.DefaultInstance
.VerifyIdTokenAsync(idToken);
string uid = decodedToken.Uid;
ID 令牌验证需要项目 ID。 Firebase Admin SDK 尝试通过以下方法之一获取项目 ID:
- 如果 SDK 使用显式
projectId
app 选项初始化,则 SDK 使用该选项的值。 - 如果 SDK 是使用服务帐号凭据初始化的,则 SDK 使用服务帐号 JSON 对象的
project_id
字段。 - 如果设置了
GOOGLE_CLOUD_PROJECT
环境变量,SDK 会使用其值作为项目 ID。此环境变量可用于在 Google 基础架构(例如 App Engine 和 Compute Engine)上运行的代码。
使用第三方 JWT 库验证 ID 令牌
如果您的后端使用 Firebase Admin SDK 不支持的语言,您仍然可以验证 ID 令牌。首先,为您的语言找到第三方 JWT 库。然后,验证 ID 令牌的标头、有效负载和签名。
验证 ID 令牌的标头是否符合以下约束:
ID 令牌标头声明 | ||
---|---|---|
alg | 算法 | "RS256" |
kid | 密钥 ID | 必须对应于https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com 中列出的公钥之一 |
验证 ID 令牌的负载是否符合以下约束:
ID 令牌有效负载声明 | ||
---|---|---|
exp | 到期时间 | 必须在未来。自 UNIX 纪元以来的时间以秒为单位。 |
iat | 发行时间 | 一定是过去。自 UNIX 纪元以来的时间以秒为单位。 |
aud | 观众 | 必须是您的 Firebase 项目 ID,即您的 Firebase 项目的唯一标识符,可以在该项目控制台的 URL 中找到。 |
iss | 发行人 | 必须是"https://securetoken.google.com/<projectId>" ,其中<projectId> 与上面用于aud 的项目 ID 相同。 |
sub | 主题 | 必须是非空字符串,并且必须是用户或设备的uid 。 |
auth_time | 认证时间 | 一定是过去。用户认证的时间。 |
最后,确保 ID 令牌由与令牌的kid
声明对应的私钥签名。从https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com
获取公钥并使用 JWT 库来验证签名。使用来自该端点的响应的Cache-Control
标头中的max-age
值来了解何时刷新公钥。
如果上述所有验证都成功,您可以使用 ID 令牌的主题( sub
)作为相应用户或设备的uid
。