Firebase .NET 令牌验证

Posted

技术标签:

【中文标题】Firebase .NET 令牌验证【英文标题】:Firebase .NET Token Verification 【发布时间】:2017-02-17 17:02:52 【问题描述】:

正在处理使用 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,我们采用了第 3 方 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 获取公钥

我们一直在研究文档和 *** 很长时间,但我们找不到使用此公钥的方法,如 Firebase 文档所述:

最后,确保 ID 令牌由与令牌的 Kid 声明对应的私钥签名。从https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com 获取公钥并使用 JWT 库来验证签名。

Firebase 文档并没有对此提供任何解释,我们正在使用的库的文档也没有提供任何解释。因此,当我们得到的只是公钥时,我们甚至无法获得关于如何验证令牌是否由私钥签名的基本概念。

验证令牌是否确实由正确的私钥签名的最佳方法是什么?

【问题讨论】:

【参考方案1】:

在 Startup.cs 中使用以下代码 sn-p 创建一个服务,该服务在收到对服务器的请求时自动验证 JWT 令牌。使用此代码 sn-p 后,您必须在控制器类文件中使用 [ApiController] 上方的 [Authorize] 属性来强制程序进行身份验证,然后才能访问该特定控制器类中的操作方法。

public void ConfigureServices(IServiceCollection services)

    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => 
        options.Authority = "https://securetoken.google.com/<PROJECT ID>";
        options.TokenValidationParameters = new TokenValidationParameters 
            ValidIssuer = "https://securetoken.google.com/<PROJECT ID>",
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidAudience = "<PROJECT ID>",
            ValidateLifetime = true
        ;
    );


public void Configure(IApplicationBuilder app, IWebHostEnvironment env)


    app.UseAuthentication();


编辑>你应该如何将令牌发送到服务器。

如您所见,您必须发送带有 Authorization 标头的 Post/Get 请求。该值应为 Bearer 格式。请查看 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

【讨论】:

这对你有用吗?我不断收到 401。是否需要额外的 firebase 设置? 是的,它对我有用 :) 401 是未经授权的错误,这意味着令牌未经过验证。您必须将令牌作为承载令牌发送到服务器,这意味着标头应该具有授权标签,并且值应该是承载 . 只要您拥有令牌,您就不必再进一步配置 firebase。如果你想测试它是否有效。登录控制台后打印 firebase 令牌,然后使用 Postman 在 Authorization 选项卡中将请求作为不记名令牌发送到您的服务器。确保在任何操作方法上方也添加 [Authorize] 属性。然后您可以执行任何操作方法来显示您的结果。如果显示,则表示您成功了。 嗨。是的,您的代码是正确的,无需在 Firebase 上执行任何其他操作。问题是我在同一个解决方案(identityServer4 和 Firebase)中使用了多个 JWT 提供程序。我必须重新定义授权的“含义”,以便让两个身份提供者验证每个令牌。这个答案对我有很大帮助:***.com/a/49706390/6357154 让机器人提供者一起工作。谢谢【参考方案2】:

现在我们可以使用适用于 .NET 的 Firebase Admin SDK。

https://github.com/Firebase/firebase-admin-dotnet

var decoded = await FirebaseAuth.DefaultInstance.VerifyIdTokenAsync(idToken);
var uid = decoded.Uid;

【讨论】:

更多信息firebase.googleblog.com/2018/08/…【参考方案3】:

Firebase 确实缺乏对 c 锐化器的支持。我为 C# 社区创建了第 3 方令牌验证库。 https://github.com/gtaylor44/FirebaseAuth

大部分代码都基于 João Angelo 的回答。我已经使用 Cache-Control["max-age"] 属性在响应标头中添加了 Web 请求的缓存,如 Firebase 所记录的那样,以获得更好的性能。

【讨论】:

【参考方案4】:

如果您像我一样使用另一个 Newtonsoft.JSON 库并且不想导入 Microsoft 库,请试试这个:https://gist.github.com/saltyJeff/41029c9facf3ba6159ac019c1a85711a

使用Verify(string token)异步验证令牌是否有效:如果有效则返回用户的唯一标识符,如果无效则返回null。

【讨论】:

【参考方案5】:

您应该能够通过执行以下操作来完成令牌验证,该操作利用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 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;

【讨论】:

获取 SecurityTokenSIgnatureKeyNotFoundException。将深入研究这一点,感谢您的起点!如果我让它与这个解决方案一起工作,我会继续接受答案。 如果您提供的安全密钥都不匹配 JWT 声明使用的安全密钥,就会发生这种情况。如果您解码jwt.io 中的令牌,您可能会在标题中找到kid 属性。该值应与从 Google 获得的列表中返回的证书之一匹配。如果不是,则说明异常。 我已经实施了您的解决方案并遇到了同样的异常。我已经根据googleapis.com/robot/v1/metadata/x509/… 的证书检查了我的令牌的孩子,它与 4 个证书之一匹配。四个证书被加载到密钥数组中,但在验证时会抛出 SecurityTokenSIgnatureKeyNotFoundException。有什么想法吗? 请注意,为此我必须安装一个额外的 Nuget 包,否则 ReadAsAsync&lt;&gt; 不会被识别为有效方法。 Install-package Microsoft.AspNet.WebApi.Clientnuget.org/packages/Microsoft.AspNet.WebApi.Client 我正在寻找一种类似的方法来验证 Azure APIM 中的 firebase 令牌,使用带有 JWKS 和颁发者密钥的 validate-jwt 策略?

以上是关于Firebase .NET 令牌验证的主要内容,如果未能解决你的问题,请参考以下文章

使用 apollo-client + firebase auth 刷新令牌

如何在 Firebase 中验证休息呼叫?

如何在 Flutter 应用程序中更新 Firebase 令牌并存储它?

在客户端检索由 firebase 分配的用户 ID 令牌时出错

使用 gcloud 服务帐户登录到 Firebase

如何验证修改后的 Firebase 令牌