【发布时间】:2016-10-13 06:26:35
【问题描述】:
我们正在尝试设置自定义身份验证,以便 Android 应用程序可以利用我们现有的身份验证系统来访问 Firebase 数据库。
移动应用根据 .NET WebAPI 端点进行身份验证。我们在响应中发回一个 Firebase 身份验证令牌,然后应用可以使用该令牌在 Firebase SDK 中进行身份验证。
根据文档,我们认为这将非常简单。使用来自 Nuget 的 FirebaseTokenGenerator 包,我们从 Firebase 控制台 > 项目 > 管理 > 数据库 > 数据库机密中找到的机密生成此令牌。
但是,当我们使用此处生成的令牌时,我们发现 Android SDK 会返回此异常:
com.google.firebase.auth.FirebaseAuthInvalidCredentialsException: The custom token format is incorrect. Please check the documentation.
at com.google.android.gms.internal.zzafd.zzes(Unknown Source)
at com.google.android.gms.internal.zzafa$zzg.zza(Unknown Source)
at com.google.android.gms.internal.zzafl.zzet(Unknown Source)
at com.google.android.gms.internal.zzafl$zza.onFailure(Unknown Source)
at com.google.android.gms.internal.zzafg$zza.onTransact(Unknown Source)
查看文档让我更加困惑,因为不清楚问题可能是什么。似乎有很多候选解决方案,但我无法弄清楚哪个是正确的。以下是文档中讨论的一些内容:
- 创建服务帐户,下载 JWT json 文件,包括 .NET WebApi 项目中的文件以及如何将其与 FirebaseTokenGenerator 一起使用
- 使用第 3 方 JWT 库从密钥生成令牌
这两种策略似乎在同一件事上,但似乎没有任何关系。
我是否使用了错误的秘密?我是否需要对我的 WebAPI 项目进行更多设置以使其生成正确的令牌?
作为参考,这是生成我的令牌的方法:
public string GetSignedFirebaseAuthToken(Agent agent, DateTime expires)
{
var tokenGenerator = new Firebase.TokenGenerator(BusinessLogicResources.FirebaseSecret);
var authPayload = new Dictionary<string, object>()
{
{ "uid", agent.AgentId.ToString() },
{ "UserName", agent.FullName },
{ "AgencyId", agent.AgencyId },
{ "AgencyName", agent.AgencyName }
};
return tokenGenerator.CreateToken(authPayload, new Firebase.TokenOptions(expires:expires));
}
更新: 这是我用来铸造我的 firebase 令牌的新代码。
public string GetSignedFirebaseAuthToken(Agent agent, DateTime expires)
{
// I set the expiry time to 3600 because this is the maximum number of seconds
// allowed according the the Firebase documenation.
var expiryTime = 3600;
// This claims object contains some additional information that Telenotes would
// like to track for each user of Firebase. This is used for reporting and
// security rules in Firebase.
var claims = new Dictionary<string, object>()
{
{ "UserName", agent.FullName },
{ "AgencyId", agent.AgencyId.ToString() },
{ "AgencyName", agent.AgencyName }
};
// In order for the cryptography algorithms to be happy, I need to put our
// keys into stream objects.
var memoryStream = new MemoryStream();
var streamWriter = new StreamWriter(memoryStream);
streamWriter.Write(BusinessLogicResources.FirebaseSecret.Replace(@"\n", "\n"));
streamWriter.Flush();
memoryStream.Position = 0;
var streamReader = new StreamReader(memoryStream);
// BouncyCastle takes care of the cryptography stuff, so we'll hand our
// secret over to BouncyCastle to read and encode.
var bouncyCastleReader = new PemReader(streamReader);
var rsaParams = (RsaPrivateCrtKeyParameters) bouncyCastleReader.ReadObject();
// Now that the secret is packed up all nicely in rsaParams, I need to
// put together the rest of the payload that Firebase needs in my auth token.
var tokenPayload = new Dictionary<string, object>()
{
{ "claims", claims },
{ "uid", agent.AgentId },
{ "iat", (DateTime.Now).SecondsSinceEpoch() },
{ "exp", (DateTime.Now).AddSeconds(expiryTime).SecondsSinceEpoch() },
{ "aud", BusinessLogicResources.FirebasePayloadAud },
{ "iss", BusinessLogicResources.FirebasePayloadISS },
{ "sub", BusinessLogicResources.FirebasePayloadSUB },
{ "alg", "RS256" }
};
// Lastly, we need to put it all together using JOSE JWT (see https://github.com/dvsekhvalnov/jose-jwt)
// and BouncyCastle encoding magic.
var rsaKey = DotNetUtilities.ToRSA(rsaParams);
return JWT.Encode(tokenPayload, rsaKey, JwsAlgorithm.RS256);
}
【问题讨论】:
-
由于您使用的是 .NET,因此您正在寻找 Create custom tokens using a third-party JWT library。文档的其他部分适用于受支持的 SDK。 BusinessLogicResources.FirebasePayload* 的值是多少?您如何验证这些与您的服务帐户电子邮件、身份 URL 等完全匹配?您能否以模糊的方式分享这些值以帮助验证?
-
另外,agent.AgentId 的值是多少?错误在哪里产生?当您尝试调用身份验证时,在客户端?您如何验证那里使用的令牌与您在此处输出的内容相匹配?这里的基本方法看起来是正确的,因为我了解任何 .NET,所以它可能在细节中。
-
错误是在客户端生成的,在 Android 应用程序中。我们已经验证了此处输出的令牌正确地通过线路到达客户端。
-
agent.AgentId 是一个 int 字段。如果这些信息对您来说还不够,请告诉我。
-
BusinessLogicResources.FirebasePayload 值... iss and sub: xxx@xxx.iam.gserviceaccount.com
标签: asp.net-web-api firebase firebase-authentication