Firebase .NET令牌验证

时间:2016-10-08 23:46:37

标签: c# firebase jwt firebase-authentication

使用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文档并未真正为此提供任何解释,我们正在使用的库文档也没有。因此,当我们给出的所有内容都是公钥时,我们甚至无法获得关于如何验证令牌是否由私钥签名的基本想法。

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

5 个答案:

答案 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

enter image description here

答案 4 :(得分:0)

Firebase实际上缺乏对c sharper的支持。我为C#社区创建了第三方令牌验证库。 https://github.com/gtaylor44/FirebaseAuth

大部分代码都基于JoãoAngelo的回答。我已根据Firebase记录的响应标头中的Cache-Control [“max-age”]属性添加了Web请求的缓存,以获得更好的性能。