Loading

Sign in with Apple 后端验证(C#)

流程请参考:https://www.cnblogs.com/ljcgood66/p/12537389.html

公钥验证

/// <summary>
    /// 验证公钥
    /// </summary>
    /// <param name="jwtToken"></param>
    /// <returns></returns>

    public static bool VerifyPublicKey(string jwtToken)
    {
        var parts = jwtToken.Split('.');
        var header = JsonConvert.DeserializeObject<JObject>(Encoding.UTF8.GetString(FromBase64(parts[0])));

        var payload = JsonConvert.DeserializeObject<JObject>(Encoding.UTF8.GetString(FromBase64(parts[1])));

        // 第三部分是验证码,用来验证数据"{header}.{payload}"
        var signagure = FromBase64(parts[2]);
        var signedOver = Encoding.UTF8.GetBytes(parts[0] + "." + parts[1]);
        var keysJson = new WebClient().DownloadString("https://appleid.apple.com/auth/keys");
        var keys = JsonConvert.DeserializeObject<JObject>(keysJson)["keys"] as JArray;
        var key = keys.OfType<JObject>().FirstOrDefault(x => (string)x["kid"] == (string)header["kid"]);
        // 这里只支持RS256签名。RS256就是使用RSA算法,用一个RSA公钥,来验证数据的SHA256摘要。
        var alg = (string)key["alg"]; if (alg != "RS256");
        var n = FromBase64((string)key["n"]);
        var e = FromBase64((string)key["e"]);
        using (var rsa = new RSACryptoServiceProvider())
        {
            // 导入RSA公钥
            rsa.ImportParameters(new RSAParameters() { Exponent = e, Modulus = n });
            // 验证数据的SHA256摘要
            var signatureVerified = rsa.VerifyData(signedOver, signagure, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
            return signatureVerified;
        }
    }
    public static byte[] FromBase64(string base64WithoutPadding)
    {
        var base64 = base64WithoutPadding.Length % 4 == 0
            ? base64WithoutPadding
            : base64WithoutPadding + new string('=', 4 - base64WithoutPadding.Length % 4);

        return Convert.FromBase64String(base64.Replace("-", "+").Replace('_', '/'));
    }

创建client_secret 

 static void Main(string[] args)
    {
        var team_id = "xxxxx";
        var ecdsaPrivateKey = ReadPrivateKey();
        var now = DateTime.UtcNow;
        var signing = new SigningCredentials(new ECDsaSecurityKey(ecdsaPrivateKey), SecurityAlgorithms.EcdsaSha256);
        var header = new JwtHeader(signing);
        var jwtHandler = new JwtSecurityTokenHandler() { };
        var payload = new JwtPayload(team_id, "https://appleid.apple.com", new List<Claim> { new Claim("sub", "xxx.xx.xxx") }, now, now.AddSeconds(86400 * 30), now);
        header.Add("kid", "xxxx");
        header.Remove("typ");
        var jwtSecurity = new JwtSecurityToken(header, payload);
        var jwtToken = jwtHandler.WriteToken(jwtSecurity);
        ecdsaPrivateKey.Dispose();
        Console.WriteLine(jwtToken);

    }

    static ECDsa ReadPrivateKey()
    {

        // 可以用BouncyCastle的ArmoredInputStream来脱壳,处理比较周全。
        var p8 =File.ReadAllText("p8文件");

        // 这里直接用去头去尾的方法:
        var lines = p8.Split('\n');
        var trimmed = string.Join("", lines.Skip(1).Take(lines.Length - 2).Select(l => l.Trim()));
        var keyBlob = Convert.FromBase64String(trimmed);

        // CngKey是微软的实现。如果你的密钥无法读出,试试用BouncyCastle来处理
        var privateKey = CngKey.Import(keyBlob, CngKeyBlobFormat.Pkcs8PrivateBlob);
        return new ECDsaCng(privateKey);
    }

 

posted @ 2020-04-15 17:02  正在缓冲  阅读(970)  评论(2编辑  收藏  举报