使用Firebase进行某些数据存储的项目,我们的客户端请求使用C#.NET实现服务器。我们在服务器上设置REST端点,以便客户端能够出于某些目的与其进行通信(例如,触发只能在服务器上运行的算法)。
Firebase建议我们通过ID令牌识别用户,如下所示:https://firebase.google.com/docs/auth/server/verify-id-tokens#verify_id_tokens_using_a_third-party_jwt_library
由于没有支持令牌身份验证的官方.NET Firebase服务器SDK,我们已经使用第三方JWT库执行此操作:https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet
根据Firebase文档中的说明,我们首先生成向服务器发送令牌。在检查令牌中的几个不同字段后,我们使用kid
字段从https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com获取公钥
我们一直在浏览文档和StackOverflow很长一段时间,但我们无法使用此公钥来执行此操作,如Firebase文档所指定的那样:
最后,确保ID令牌由与令牌的孩子声明相对应的私钥签名。从https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com获取公钥并使用JWT库验证签名。
Firebase文档并未真正为此提供任何解释,我们正在使用的库文档也没有。因此,当我们给出的所有内容都是公钥时,我们甚至无法获得关于如何验证令牌是否由私钥签名的基本想法。
验证令牌是否由正确的私钥实际签名的最佳方法是什么?
答案 0 :(得分:6)
您应该能够通过执行以下操作来完成令牌验证,该操作利用System.IdentityModel.Tokens.Jwt
Nuget包执行大多数验证:
class Program {
static HttpClient client = new HttpClient();
static void Main() { RunAsync().Wait(); }
static async Task RunAsync() {
string encodedJwt = "[TOKEN_TO_BE_VALIDATED]";
// 1. Get Google signing keys
client.BaseAddress = new Uri("https://www.googleapis.com/robot/v1/metadata/");
HttpResponseMessage response = await client.GetAsync(
"x509/securetoken@system.gserviceaccount.com");
if (!response.IsSuccessStatusCode) { return; }
var x509Data = await response.Content.ReadAsAsync<Dictionary<string, string>>();
SecurityKey[] keys = x509Data.Values.Select(CreateSecurityKeyFromPublicKey).ToArray();
// 2. Configure validation parameters
const string FirebaseProjectId = "[FIREBASE_PROJECT_ID]";
var parameters = new TokenValidationParameters {
ValidIssuer = "https://securetoken.google.com/" + FirebaseProjectId,
ValidAudience = FirebaseProjectId,
IssuerSigningKeys = keys,
};
// 3. Use JwtSecurityTokenHandler to validate signature, issuer, audience and lifetime
var handler = new JwtSecurityTokenHandler();
SecurityToken token;
ClaimsPrincipal principal = handler.ValidateToken(encodedJwt, parameters, out token);
var jwt = (JwtSecurityToken)token;
// 4.Validate signature algorithm and other applicable valdiations
if (jwt.Header.Alg != SecurityAlgorithms.RsaSha256) {
throw new SecurityTokenInvalidSignatureException(
"The token is not signed with the expected algorithm.");
}
}
static SecurityKey CreateSecurityKeyFromPublicKey(string data) {
return new X509SecurityKey(new X509Certificate2(Encoding.UTF8.GetBytes(data)));
}
}
示例程序的using语句列表:
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net.Http;
using System.Security.Claims;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Tokens;
答案 1 :(得分:1)
如果您正在使用像我这样的其他Newtonsoft.JSON库并且不想导入Microsoft的库,请尝试以下方法:https://gist.github.com/saltyJeff/41029c9facf3ba6159ac019c1a85711a
使用Verify(string token)
异步验证令牌是否有效:如果有效,则返回用户的唯一标识符;如果无效,则返回null。
答案 2 :(得分:1)
现在我们可以将Firebase Admin SDK用于.NET。
https://github.com/Firebase/firebase-admin-dotnet
var decoded = await FirebaseAuth.DefaultInstance.VerifyIdTokenAsync(idToken);
var uid = decoded.Uid;
答案 3 :(得分:1)
在 Startup.cs 中使用以下代码片段创建一个服务,该服务在服务器收到请求时自动验证 JWT 令牌。使用此代码片段后,您必须使用控制器类文件中 [ApiController] 上方的 [Authorize] 属性来强制程序进行身份验证,然后才能访问该特定控制器类中的操作方法。
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
alignment: Alignment.center,
children: [
Center(
child: Container( // Your Image
height: 100,
width: 100,
child: Placeholder(),
),
),
Positioned(
bottom: 0,
child: Container( // Your Button
height: 30,
width: 100,
child: Placeholder(),
),
)
],
),
);
}
}
编辑>您应该如何将令牌发送到服务器。
如您所见,您必须发送带有 Authorization 标头的 Post/Get 请求。该值应采用承载格式。请查看 firebase 文档以了解如何从经过身份验证的用户那里提取令牌 ID。
https://firebase.google.com/docs/reference/node/firebase.auth.Auth#signinwithemailandpassword https://firebase.google.com/docs/reference/node/firebase.auth#usercredential https://firebase.google.com/docs/reference/node/firebase.User#getidtoken
答案 4 :(得分:0)
Firebase实际上缺乏对c sharper的支持。我为C#社区创建了第三方令牌验证库。 https://github.com/gtaylor44/FirebaseAuth
大部分代码都基于JoãoAngelo的回答。我已根据Firebase记录的响应标头中的Cache-Control [“max-age”]属性添加了Web请求的缓存,以获得更好的性能。