我在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();
}
引用的路径是我使用openssl从用于编码jwt的私钥生成的pem格式化公钥。我试图按照.NET Core的这个例子 - JWT Validation and Authorization in ASP.NET Core - 但当然整个auth中间件配置已经在2.0中移动到ConfigureServices方法,并且不再有AutomaticAuthorization选项。
一切似乎都很好,但我得到的是401 - 未经授权的持票人错误=&#34; invalid_token&#34;使用标题作为Authorization: Bearer TOKEN
发出请求时出错。无论如何,我希望有人可以就我可能出错的地方和/或我如何进一步排除故障给出一些建议。
答案 0 :(得分:0)
所以,对于想要运行同一类型场景的人来说,我想到了这一点。
我的第一个问题是我使用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]属性保护的端点。