为 Epic 后端身份验证创建 JWT

问题描述 投票:0回答:1

我正在尝试通过后端应用程序连接到 Epic 沙箱环境。我一直在遵循这个指南,但我认为我的 JWT 签名遇到了问题。这是我用来生成令牌的代码

class CreateJwt
{
    public static string? Token { get; set; }
    public static void Jwt()
    {

        try
        {
            
            // reading the content of a private key PEM file
            string privateKeyPem = File.ReadAllText("./private_epic_backend_key.pem");

            // keeping only the payload of the key 
            privateKeyPem = privateKeyPem.Replace("-----BEGIN PRIVATE KEY-----", "");
            privateKeyPem = privateKeyPem.Replace("-----END PRIVATE KEY-----", "");

            byte[] privateKeyRaw = Convert.FromBase64String(privateKeyPem);

            // creating the RSA key 
            RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
            provider.ImportPkcs8PrivateKey(new ReadOnlySpan<byte>(privateKeyRaw), out _);
            RsaSecurityKey rsaSecurityKey = new RsaSecurityKey(provider);

            // Generating the token 
            var now = DateTime.UtcNow;

            var claims = new[] {
                new Claim(JwtRegisteredClaimNames.Iss, "1a467f07-8a84-4e25-a493-4ba9d5ef9054"),
                new Claim(JwtRegisteredClaimNames.Sub, "1a467f07-8a84-4e25-a493-4ba9d5ef9054")
            };

            var handler = new JwtSecurityTokenHandler();

            var token = new JwtSecurityToken
            (
                "1a467f07-8a84-4e25-a493-4ba9d5ef9054",
                "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token",
                claims,
                now.AddMilliseconds(-30),
                now.AddMinutes(4),
                new SigningCredentials(rsaSecurityKey, SecurityAlgorithms.RsaSha384)
            );

            // handler.WriteToken(token) returns the token ready to send
            Token = handler.WriteToken(token);
            Console.WriteLine(Token);

        }

        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            Console.WriteLine(
                 new System.Diagnostics.StackTrace().ToString()
            );
        }

    }
}

我认为问题出在签名上的原因是,当我将令牌加载到 JWT.IO 中时,我收到“无效签名”响应。然后这是我发送的代码。

class GetBearerToken
{
    private static readonly HttpClient client = new HttpClient();
    public static string? Bearer { get; set; }

public async static Task Authorize()
    {
        try
        {
            var values = new Dictionary<string, string>
            {
                { "grant_type", "client_credentials" },
                { "client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" },
                { "client_assertion", CreateJwt.Token }
            };

            var content = new FormUrlEncodedContent(values);

            content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");

            var requeststring = await content.ReadAsStringAsync();
            Console.WriteLine(requeststring);

            var response = await client.PostAsync("https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token", content);

            var responseString = await response.Content.ReadAsStringAsync();

            Console.WriteLine("response from post");
            Console.WriteLine(responseString);
           
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            Console.WriteLine(
                 new System.Diagnostics.StackTrace().ToString()
            );
        }
    }
}

这看起来与他们根据 Epic 提供的文档所期望的完全一样,但我得到的回报是

“错误”:“无效的客户端”, “错误描述”:空

Epic 提供了一个故障排除文档来解决这个特定的错误,但它似乎更像是一个包罗万象的错误。我已经执行了两次故障排除步骤,但仍然无法克服此错误。

任何帮助将不胜感激。

c# jwt rsa
1个回答
0
投票
 // This is the refactoring of these two classes that will work:
 // env. .NET 7

 using System.IdentityModel.Tokens.Jwt;
 using System.Net.Http.Headers;
 using System.Security.Claims;
 using System.Security.Cryptography;

 using Microsoft.IdentityModel.Tokens;

 namespace EPICAPI.AppTest
 {
     public class Program
     {
         static void Main(string[] args)
         {
             _ = GetBearerToken.Authorize();
         }
     }

     public static class CreateJwt
     {
         public static string Jwt()
         {
             try
             {
                 // reading the content of a private key PEM file
                 string privateKeyPem = File.ReadAllText(@"L:\OpenSSL\keys\privatekey.pem");

                 // keeping only the payload of the key 
                 privateKeyPem = privateKeyPem.Replace("-----BEGIN PRIVATE KEY-----", string.Empty);
                 privateKeyPem = privateKeyPem.Replace("-----END PRIVATE KEY-----", string.Empty);
                 byte[] privateKeyRaw = Convert.FromBase64String(privateKeyPem);

                 // Generating the token 
                 DateTime now = DateTime.UtcNow;

                 Guid gJti = Guid.NewGuid(); // you may improve this

                 IEnumerable<Claim> claims = new[] {
                    // new Claim(JwtRegisteredClaimNames.Iss, "xxxxx-xxx-xxx-xx-xxx"), // do not use this (Iss) in claims
                    new Claim(JwtRegisteredClaimNames.Sub, "xxxxx-xxx-xxx-xx-xxx"),
                    new Claim(JwtRegisteredClaimNames.Jti, gJti.ToString())
                 };

                 JwtSecurityTokenHandler handler = new();

                 // creating the RSA key 
                 RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
                 provider.ImportPkcs8PrivateKey(new ReadOnlySpan<byte>(privateKeyRaw), out _);

                 RsaSecurityKey rsaSecurityKey = new RsaSecurityKey(provider);

                 JwtSecurityToken jwtToken = new JwtSecurityToken
                 (
                     issuer: "xxxxx-xxx-xxx-xx-xxx",
                     audience: "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token",
                     claims: claims,
                     notBefore: now.AddMilliseconds(-30),
                     expires: now.AddMinutes(4),
                     signingCredentials: new SigningCredentials(rsaSecurityKey, SecurityAlgorithms.RsaSha384)
                 );

                 string accessToken = new JwtSecurityTokenHandler().WriteToken(jwtToken);
                 Console.WriteLine(accessToken);

                 return accessToken;
             }
             catch (Exception e)
             {
                 Console.WriteLine(e.ToString());
                 Console.WriteLine(new System.Diagnostics.StackTrace().ToString());

                 return string.Empty;
             }
         }
     }

     public static class GetBearerToken
     {
         public static void Authorize()
         {
             string token = CreateJwt.Jwt();

             try
             {
                 HttpClient client = new();
                 HttpRequestMessage request = new(HttpMethod.Post, "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token");

                 List<KeyValuePair<string, string>> values = new()
                 {
                     new("grant_type", "client_credentials"),
                     new("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"),
                     new("client_assertion", token)
                 };

                 FormUrlEncodedContent content = new(values);

                 request.Content = content;

                 HttpResponseMessage response = client.Send(request);

                 response.EnsureSuccessStatusCode();

                 Console.WriteLine(response.Content.ReadAsStringAsync());
             }
             catch (Exception e)
             {
                 Console.WriteLine(e.ToString());
                 Console.WriteLine(new System.Diagnostics.StackTrace().ToString());
             }
         }
     }
 }
© www.soinside.com 2019 - 2024. All rights reserved.