我正在使用IdentityServer4生成JWT。这是使用角度发送到SPA。 SPA可以解码令牌并获得索赔,例如作用。
const tokenPayload = jwt_decode(token);
return tokenPayload.role === expectedRole;
同样的令牌被发送到NodeJS中的API。我尝试使用jsonwebtoken对JWT进行解码,但我无法解码它。
const token = ExtractJwt.fromAuthHeaderAsBearerToken()(req);
console.log('Reading token: ' + token);
const decoded = jwt.verify(token, 'supersecret',
{
typ:"JWT",
algorithms: ["RS256"],
issuer: 'http://localhost:5500',
audience: 'adApi' }
);
console.log('Decoded token: ' + decoded);
我一直收到错误: “错误:错误:0906D06C:PEM例程:PEM_read_bio:无起始行”
我理解文档说我应该使用PEM文件而不是'supersecret'。
问题:为什么“jwt_decode”可以轻松解码令牌?如何生成PEM文件。
这是我正在使用的配置信息。让我提醒您,这是使用IdentityServer4的ASPNET核心身份。
using IdentityServer4;
using IdentityServer4.Models;
using System.Collections.Generic;
namespace XYZ.Identity
{
public class IdentityServerConfig
{
// scopes define the resources in your system
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile()
};
}
public static IEnumerable<ApiResource> GetApiResources()
{
return new[]
{
new ApiResource
{
Name = "adApi",
DisplayName = "adApi Resource",
Description = "XYZ Admin API",
ApiSecrets = { new Secret("supersecret".Sha256()) },
Scopes = { new Scope("adApi") },
UserClaims = {
"name", "role"
}
}
};
}
public static IEnumerable<Client> GetClients()
{
// client credentials client
return new List<Client>
{
new Client
{
ClientId = "apiclientid",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
ClientSecrets =
{
new Secret("supersecret".Sha256())
},
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"adApi"
}
}
};
}
}
}
提前谢谢!
答案 0 :(得分:0)
jwt_decode
只是解码令牌而不验证签名。没有必要在前端验证签名,因为如果没有后端已经验证授权,你就不会有任何秘密。
要尝试使用对称签名密钥签名的令牌,您需要将algorithm
从RS256
更改为对称签名,例如HS256
(对于verify
您可以将它添加到允许的算法数组中。)
答案 1 :(得分:0)
Ok. I was able to understand what happened.
In the IdentityServer4 implementation for ASP.NET Core there is an "implicit" RSA key/cert being created. The AddDeveloperSigningCredential() in the following code causes the tempkey.rsa file to be created.
services.AddIdentityServer() .AddDeveloperSigningCredential() //.AddSigningCredential(new X509Certificate2(Path.Combine(".", "certs", "IdentityServer4Auth.pfx"))) .AddInMemoryPersistedGrants() .AddInMemoryIdentityResources(IdentityServerConfig.GetIdentityResources()) .AddInMemoryApiResources(IdentityServerConfig.GetApiResources()) .AddInMemoryClients(IdentityServerConfig.GetClients()) .AddAspNetIdentity();
This file is used by IdentityServer4 to sign the tokens.
In order to verify the token, that is to check if the token has not been tampered with, you need the public key to be generated. For that, you can open the rsa file which is in JSON format and using this tool you can generate the PEM content which is the public key.
I saved the file in my NodeJS server and used the following code to verify and then decode.
const token = ExtractJwt.fromAuthHeaderAsBearerToken()(req); console.log('Reading token: ' + token + "==");
// verify a token asymmetric var cert = fs.readFileSync('public-key.pem'); // get public key jwt.verify(token, cert, function(err, decoded) { if(err) //Error logic //verify token expire date console.log(decoded) // bar });
var decoded = jwt.decode(token); var userId = decoded.name;
The trick was to understand that the RSA file was being generated and the the pulic key gad to be generated separately. This might be obvious once you've done it but for new people in the certificates world it might be that obvious.
答案 2 :(得分:0)
根据上面的答案,我做了实验,我无法直接回复上述答案,因为我还不够,所以我不得不直接回复。
我根据identityserver4演示示例编写代码,使用.AddDeveloperSigningCredential(),所以我在identityserver4服务器项目中看到tempkey.rsa,我用记事本打开,然后复制Modulus数据,然后使用https :// superdry.apphb.com/tools/online-rsa-key-converter工具生成PEM文件,然后我在快速中间件中使用以下代码。 PEM文件,我刚刚生成了PEM文件。然后我成功验证了identityserver4发布的令牌Var cert = fs.readFileSync ('demo2.pem');
Jwt.verify (token, Cert, function (err, decoded) {
If (ERR) {
Console.log (ERR);
}else{
Console.log (decoded);
//Error logic //verify token expire date} console.log (decoded / bar)
});
但这里有几个问题
1,我们不应该把模块数据生成PEM,然后复制到nodejs项目,因为它不是最好的解决方案,如果我们修改idrv4服务器密钥,我们必须重建PEM文件,然后复制对应于nodejs的服务器,它是愚蠢的。我检查了一些信息,你可以通过这个地址看到http://localhost:5000/.well-known/openid-configuration/jwks的密钥加密,但是有一个巨大的bug,我在浏览器中看到打开上面的内容如下{
Keys: [
{
Kty: "RSA",
Use: "sig",
Kid: "4df1e1f19d477d97efeffe3548418c60",
E: "AQAB",
N: "**XXXX**",
Alg: "RS256"
}
]
}
但是我用记事本打开的tempkey.rsa文件中的模块数据是 的 XXXX == 强> 因为实际上模块的数据应该与上面n所示的数据相同,但是通过 访问N个数据,甚至比模块内部的数据更少 == 2个字符,当我在这个东西生成的PEM文件面前陷入悲惨的时候。
2,所以我们仍需要启动nodejs的API,在http://localhost:5000/.well-known/openid-configuration/jwks内获取密钥,然后生成PEM文件以验证令牌签名。但要注意政府的缺席。但是如果您的idrv4使用其他加密方法,例如x509等,则密钥将不是n的值。它可能是别的东西。我还没有清楚地研究它。
最后我找到了npm包jwk-to-pem 你可以从http://localhost:5000/.well-known/openid-configuration/jwks
获取密钥var jwt = require('jsonwebtoken');
var fs = require('file-system');
var jwkToPem = require('jwk-to-pem');
var pem = jwkToPem(jwk);
console.log(pem);
// verify a token asymmetric
jwt.verify(token, pem, function(err, decoded) {
if(err){
console.log(err);
}else{
console.log(decoded);
} //Error logic //verify token expire date console.log(decoded) // bar
});