【问题标题】:Bearer error="invalid_token" from .net core 2.0来自 .net core 2.0 的承载错误 =“invalid_token”
【发布时间】:2018-06-04 14:45:19
【问题描述】:

我在 PHP 中设置了一个身份验证系统,我试图用它来将 JSON Web 令牌发送到客户端应用程序,以便应用程序访问 .net core 2.0 api。因此,身份验证服务器获取用户凭据,如果凭据通过,它会使用我使用 openssl 创建的公钥/私钥对生成令牌。我正在使用此处的过程生成令牌:http://www.phpbuilder.com/articles/application-architecture/security/using-a-json-web-token-in-php.html

我可以用 jwt.io 解码生成的令牌就好了。解码后的版本如下:

{
  "typ": "JWT",
  "alg": "HS256"
}

{
  "iss": "https://crm.advtis.com",
  "exp": "2017-12-21 18:14:42",
  "aud": "https://localhost:44354",
  "data": {
    "username": "pwalter@advtis.com",
    "role": 1
  }
}

我可以从用于对令牌进行编码的私钥文件中输入字符串,jwt.io 表示签名有效。

所以现在我想将令牌连同请求一起发送到我的 API 以获取对该资源的访问权限,该资源在调试时可在 localhost 上找到。以下是与此相关的 .NET 2.0 启动代码:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<SmartRxDBContext>();

            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                options.Audience = "https://localhost:44354/";
                options.TokenValidationParameters = new TokenValidationParameters {
                    ValidateIssuerSigningKey = true,
                    ValidateIssuer = true,
                    ValidIssuer = "https://crm.advtis.com/",
                    IssuerSigningKey = new X509SecurityKey(new X509Certificate2("C:\\Path\\To\\webOrders-cert-AspNetPubkey.cert"))
                };
            });
            services.AddMvc();
        }

引用的路径是我从用于编码 jwt 的私钥生成的 pem 格式的公钥,也是使用 openssl。我试图在 .NET Core 中遵循这个示例 - JWT Validation and Authorization in ASP.NET Core - 但当然整个 auth 中间件配置已在 2.0 中移至 ConfigureServices 方法,并且不再有 AutomaticAuthorization 选项。

一切似乎都很好,但我收到 401 - Unauthorized Bearer error="invalid_token" 错误,当使用标题为 Authorization: Bearer TOKEN 发出请求时,我希望有人能给我一些关于我在哪里的建议可能会出错和/或如何进一步排除故障。

【问题讨论】:

    标签: php .net-core jwt


    【解决方案1】:

    所以,我为任何想要运行这种相同类型场景的人解决了这个问题。

    我的第一个问题是我使用 HMAC 在 PHP 端生成令牌。 HMAC 不是公共/私有对算法。我用 composer 安装了 firebase/php-jwt 库,并用它来生成我的令牌,如下所示:

    use \Firebase\JWT\JWT;
    $token = array(      
    "iss" => "https://crm.advtis.com",
    "exp" => time()+10000,
    "aud" => "https://localhost:44354",
    "data" => array(
        "username" => "pwalter@advtis.com",
        "role" => 1
    )
    );
    
    $jwt = JWT::encode($token, file_get_contents("../path/to/private.key"), 'RS256');
    

    密钥文件是在命令行中使用 OpenSSL 生成的。我使用相同的实用程序来生成带有私钥的公钥。这两个文件都是 PEM 格式。

    接下来我要做的就是将公钥放入 .NET。我发现使用 RSACryptoServiceProvider 的最简单方法是这样的:

    private static RSACryptoServiceProvider myRSA = new RSACryptoServiceProvider();
    public void ConfigureServices(IServiceCollection services)
        {
            JwtHelper.FromXmlString(myRSA, "C:\\Users\\Path\\To\\xmlPubKey.xml");
            services.AddDbContext<SmartRxDBContext>();
    
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters {
                    ValidateIssuerSigningKey = true,
                    ValidateIssuer = true,
                    ValidIssuer = "https://crm.advtis.com",
                    ValidateAudience = true,
                    ValidAudience = "https://localhost:44354",
                    IssuerSigningKey = new RsaSecurityKey(myRSA.ExportParameters(false))
                };
            });
            services.AddMvc();
    
        }
    

    JwtHelper.FromXml() 方法改编自here,因为在 .NET 2.0 中无法从 RSA Provider 中的 XML 导入或设置参数,因此该方法解析 XML 并像这样设置参数:

    public static void FromXml(this RSA rsa, string filepath)
        {
            RSAParameters parameters = new RSAParameters();
    
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(filepath);
    
            if (xmlDoc.DocumentElement.Name.Equals("RSAKeyValue"))
            {
                foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)
                {
                    switch (node.Name)
                    {
                        case "Modulus": parameters.Modulus = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                        case "Exponent": parameters.Exponent = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                        case "P": parameters.P = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                        case "Q": parameters.Q = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                        case "DP": parameters.DP = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                        case "DQ": parameters.DQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                        case "InverseQ": parameters.InverseQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                        case "D": parameters.D = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                    }
                }
            }
            else
            {
                throw new Exception("Invalid XML RSA key.");
            }
    
            rsa.ImportParameters(parameters);
        }
    

    这就是它的要点。现在我可以从我的 PHP 服务器向客户端应用程序发出 JWT。然后我可以将 JWT 发送到我的 .NET Core 2.0 API 以访问受 [Authorize] 属性保护的端点。

    【讨论】:

      猜你喜欢
      • 2022-07-27
      • 1970-01-01
      • 2020-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-12
      • 2018-01-23
      相关资源
      最近更新 更多