简体   繁体   English

Firebase .NET 令牌验证

[英]Firebase .NET Token Verification

Working on a project that uses Firebase for some data storage, and our client requests that the server be implemented with C#.NET.处理一个使用 Firebase 进行一些数据存储的项目,我们的客户端请求使用 C#.NET 实现服务器。 We're setting up REST endpoints on the server so that the client is able to communicate with it for a few purposes (for example, triggering an algorithm to run which can only occur on the server).我们正在服务器上设置 REST 端点,以便客户端能够出于几个目的与其进行通信(例如,触发只能在服务器上运行的算法)。

Firebase recommends we identify users via an ID token, as noted here: https://firebase.google.com/docs/auth/server/verify-id-tokens#verify_id_tokens_using_a_third-party_jwt_library Firebase 建议我们通过 ID 令牌识别用户,如下所述: https : //firebase.google.com/docs/auth/server/verify-id-tokens#verify_id_tokens_using_a_third-party_jwt_library

Since there is no official .NET Firebase server SDK that supports token authentication, we've resorted to using a 3rd-party JWT library to do this: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet由于没有支持令牌身份验证的官方 .NET Firebase 服务器 SDK,我们求助于使用 3rd-party JWT 库来执行此操作: https : //github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for -dotnet

As specified in the Firebase documentation, we're first generating a sending a token to the server.正如 Firebase 文档中所指定的,我们首先生成一个向服务器发送的令牌。 After checking a few different fields in the token, we're using the kid field to grab the public key from https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com在检查令牌中的几个不同字段后,我们使用kid字段从https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com获取公钥

We've been digging around through documentation and StackOverflow for a long time, but we can't find a way to use this public key to do this, as specified by the Firebase documentation:我们已经通过文档和 StackOverflow 进行了很长时间的挖掘,但我们找不到使用此公钥来执行此操作的方法,如 Firebase 文档所指定的:

Finally, ensure that the ID token was signed by the private key corresponding to the token's kid claim.最后,确保 ID 令牌由与令牌的孩子声明对应的私钥签名。 Grab the public key from https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com and use a JWT library to verify the signature.https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com 获取公钥并使用 JWT 库来验证签名。

The Firebase documentation doesn't really offer any explanation for this, and neither does the documentation for the library we are using. Firebase 文档并没有真正对此提供任何解释,我们正在使用的库的文档也没有提供任何解释。 So we've not been able to even get a basic idea as to how we could possibly verify the token was signed by a private key when all we are given is the public key.因此,当我们得到的只是公钥时,我们甚至无法获得关于如何验证令牌是否由私钥签名的基本想法。

What would be the best way to verify that the token was actually signed by the correct private key?验证令牌实际上是由正确的私钥签名的最佳方法是什么?

You should be able to accomplish the token validation by doing something like the following, which leverages theSystem.IdentityModel.Tokens.Jwt Nuget package to perform most the validations:您应该能够通过执行以下操作来完成令牌验证,它利用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)));
  }
}

List of using statements for sample program:示例程序的 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;

Now we can use the Firebase Admin SDK for .NET.现在我们可以使用 Firebase Admin SDK for .NET。

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

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

If you're using another Newtonsoft.JSON library like me and don't want to import the Microsoft one, try this one: https://gist.github.com/saltyJeff/41029c9facf3ba6159ac019c1a85711a如果你像我一样使用另一个 Newtonsoft.JSON 库并且不想导入微软的库,试试这个: https : //gist.github.com/saltyJeff/41029c9facf3ba6159ac019c1a85711a

Use Verify(string token) to asynchronously verify that a token is valid: returns the unique identifier of the user if valid, and null if invalid.使用Verify(string token)异步验证令牌是否有效:如果有效则返回用户的唯一标识符,如果无效则返回 null。

Use the following code snippet in Startup.cs to create a service that automatically validates the JWT token when a request received to the server.使用 Startup.cs 中的以下代码片段创建一个服务,该服务在服务器收到请求时自动验证 JWT 令牌。 After using this code snippet, you have to use [Authorize] attribute above [ApiController] in controller class file(s) to force program to authenticate before giving access to the action methods in that particular controller class.使用此代码片段后,您必须在控制器类文件中使用 [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();

}

Edit> How you should send the Token to the server.编辑>您应该如何将令牌发送到服务器。

As you see, you have to send a Post/Get request with Authorization header.如您所见,您必须发送带有 Authorization 标头的 Post/Get 请求。 The value should be in Bearer format.该值应采用承载格式。 Please check firebase documentation to find out how to extract the token id from an authenticated user.请查看 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 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

在此处输入图片说明

Firebase has a real lack of support for c sharpers. Firebase 确实缺乏对 c 锐化器的支持。 I've created a 3rd party token verification library for the C# community.我为 C# 社区创建了一个 3rd 方令牌验证库。 https://github.com/gtaylor44/FirebaseAuth https://github.com/gtaylor44/FirebaseAuth

Most of the code is based on João Angelo's answer.大部分代码基于 João Angelo 的回答。 I've added caching of the web request using the Cache-Control["max-age"] property in response header as documented by Firebase for better performance.我在响应标头中使用 Cache-Control["max-age"] 属性添加了 Web 请求的缓存,如 Firebase 所述,以提高性能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM