【问题标题】:C# Firebase JWT Token VerificationC# Firebase JWT 令牌验证
【发布时间】:2018-06-12 20:58:56
【问题描述】:

我正在尝试验证从 C# 服务器上的客户端 Firebase API 发送的令牌。我几乎尝试了所有方法,但由于某种原因,我无法正确获取令牌验证方法。我已经实现了从网络获取公钥的所有内容,但我似乎无法弄清楚让 RS256 算法等于 JWT 的第三块。

class FirebaseJWTAuth {
    public string FirebaseId;
    private HttpClient Req;

    //initialize all the settings
    public FirebaseJWTAuth(string firebaseId) {
        firebaseId = FirebaseId;
        Req = new HttpClient();
        Req.BaseAddress = new Uri("https://www.googleapis.com/robot/v1/metadata/");
    }

    //given a token, return the user id as a string if valid, null if invalid
    public async Task<string> Verify(string token) {
        //following instructions from https://firebase.google.com/docs/auth/admin/verify-id-tokens

        string hashChunk = token; //keep for hashing later on
        hashChunk = hashChunk.Substring(0, hashChunk.LastIndexOf('.'));

        token = token.Replace('-', '+').Replace('_', '/'); //sanitize for base64 on C#

        string[] sections = token.Split('.'); //split into 3 sections according to JWT standards
        JwtHeader header = B64Json<JwtHeader>(sections[0]);

        //verify the header
        if(header.alg != "RS256") {
            return null;
        }

        //get the public keys
        HttpResponseMessage res = await Req.GetAsync("x509/securetoken@system.gserviceaccount.com"); //make async
        string keyDictStr = await res.Content.ReadAsStringAsync();
        Dictionary<string, string> keyDict = JsonConvert.DeserializeObject<Dictionary<string, string>>(keyDictStr);
        string keyStr = null;
        keyDict.TryGetValue(header.kid, out keyStr);
        if(keyStr == null) {
            return null;
        }

        //Use the RSACryptoServiceProvider to verify the hash
        var rsaCrypto = CertFromPem(keyStr);
        byte[] plainText = Encoding.UTF8.GetBytes(hashChunk);
        byte[] hashed = SHA256Managed.Create().ComputeHash(plainText);
        byte[] encrypted = rsaCrypto.Encrypt(hashed, false);

        byte[] challenge = SafeB64Decode(sections[2]);

        Console.WriteLine(encrypted.SequenceEqual(challenge)); //QUESTION IN THE ISSUE: expect to be true, but always false

        //for debugging purposes
        Console.WriteLine(Convert.ToBase64String(challenge));
        Console.WriteLine(Convert.ToBase64String(encrypted));

        return "didn't really get down to this part";
    }

    //given a string, return the RSACryptoServiceProvider which corresponds to the public key
    static RSACryptoServiceProvider CertFromPem(string pemKey) {
        X509Certificate2 cert = new X509Certificate2();
        cert.Import(Encoding.UTF8.GetBytes(pemKey));
        Console.WriteLine(cert.ToString());
        return (RSACryptoServiceProvider) cert.PublicKey.Key;
    }

    //b64 decoding with padding to calm the C# converter
    static byte[] SafeB64Decode(string encoded) {
        string encodedPad = encoded + new string('=', encoded.Length % 4);
        return Convert.FromBase64String(encodedPad);
    }
    static string SafeB64DecodeStr(string encoded) {
        return Encoding.UTF8.GetString(SafeB64Decode(encoded));
    }
    static T B64Json<T> (string encoded) {
        string decoded = SafeB64DecodeStr(encoded);
        Console.WriteLine(decoded);
        return JsonConvert.DeserializeObject<T>(decoded);
    }

    //structs representing the first 2 chunks of a JWT
    private struct JwtHeader {
        public string alg;
        public string kid;
    }
    private struct JwtPayload {
        public long exp;
        public long iat;
        public string aud;
        public string iss;
        public string sub;
    }
}

我知道这很粗糙(没有验证有效负载)但我无法匹配令牌。我只是一名初级开发人员,但我已尝试添加额外的 cmets 和间距以使您更容易阅读。

我一直在我的个人令牌上测试此代码,出于明显的原因我没有在此处上传。但是,如果您想测试您的代码,请转到the firebase-auth demo site 并登录。然后,打开 DevTools 控制台并输入 firebase.auth().currentUser.getIdToken(true).then(console.log)。您的令牌将在控制台中弹出。

提前致谢。

【问题讨论】:

    标签: c# firebase firebase-authentication jwt openid-connect


    【解决方案1】:

    /掌心

    我忘记了 RSA 签名!= RSA 加密,显然 C# 对两者都有不同的库。魔术课是RSAPKCS1SignatureDeformatter

    答案是使用RSAPKCS1SignatureDeformatter.VerifySignature方法而不是基于加密的RSACryptoServiceProvider

    【讨论】:

    猜你喜欢
    • 2017-07-31
    • 2021-09-04
    • 2019-06-23
    • 2021-04-02
    • 2017-07-27
    • 2019-10-20
    • 2016-01-17
    • 2017-06-25
    • 2013-08-19
    相关资源
    最近更新 更多