我正在更新我的应用程序以将Azure Active Directory用作OAuth 2.0身份验证服务器。目前,我成功使用授权代码授权类型并接收access_token和id_token值。
现在,我正在尝试验证返回的id_token。我遵循doco中列出的步骤,我能够找到用于签署JWT的公钥。例如,这是Azure REST端点返回的记录
据我了解,这些是可用的公钥。我可以将其过滤为一个(使用返回的JWT标头中的kid值)。但我正在努力理解的是每个领域的意义。
我是否使用n / e字段为SHA256公钥创建模数和指数值?我的意思是使用x5c值吗?很抱歉,如果这是一个显而易见的问题,但是有任何文档,给定的值如上所述,如何为它创建公钥?我在Java中这样做,所以任何特定的东西都会非常感激。
答案 0 :(得分:1)
这是一个类似的question我发布并获得了帮助,这可能有所帮助。我想你想使用x5c,这是完整的证书链,并从中获取公钥来验证你的JWT的签名。模数和指数(n和e)将只生成证书链中第一个证书的公钥,但这不足以验证签名。
以下是我用于从端点提取公钥的一些代码段。 AzurePublicKey类只是json的POJO。
private PublicKey convertKey(AzurePublicKey azKey) {
PublicKey publicKey = null;
BigInteger modulus = new BigInteger(1, Base64.getUrlDecoder().decode(azKey.getN()));
BigInteger exponent = new BigInteger(1, Base64.getUrlDecoder().decode(azKey.getE()));
try {
publicKey = KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(modulus, exponent));
// load cert
CertificateFactory factory;
X509Certificate cert = null;
try {
factory = CertificateFactory.getInstance("X.509");
cert = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(DatatypeConverter.parseBase64Binary(azKey.getX5c().iterator().next())));
} catch (CertificateException e) {
e.printStackTrace();
}
// grab public key
publicKey = (RSAPublicKey)cert.getPublicKey();
System.out.println("[");
System.out.println("kid : " + azKey.getKeyIdentifier());
System.out.println("e : " + azKey.getE());
System.out.println("n : " + azKey.getN());
System.out.println("Maybe this : " + DatatypeConverter.printBase64Binary(publicKey.getEncoded()) );
System.out.println("]");
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return publicKey;
}
使用该公钥来使用JJWT库验证签名的代码。
Jws<Claims> claims = Jwts.parser()
.setSigningKeyResolver(signingKeyResolver)
.parseClaimsJws(token.replace(TOKEN_PREFIX, ""));
String issuer = claims.getBody().getIssuer();
if(issuer == null || !VALID_ISSUERS.contains(issuer))
throw new IncorrectClaimException(claims.getHeader(), claims.getBody(), "Invalid Issuer in Token.", new Throwable("Invalid Issuer in Token."));
SigningKeyResolverImpl只根据令牌标头的kid
提供正确的公钥。如果解析没有抛出异常,您可以针对您期望的值验证令牌声明,因为我已根据我期待的VALID_ISSUERS
列表验证了此处的发布者。
已经有一段时间了,所以我很模糊,但我希望这会有所帮助。
答案 1 :(得分:0)
要验证id_token的签名,如果您使用C#进行开发,我们可以使用JwtSecurityTokenHandler
类。您可以将JsonWebTokenValidator.cs引用代码示例以使用此类。为方便起见,我也在这里复制这个课程:
public class JsonWebTokenValidator
{
public JwtSecurityToken Validate(string token)
{
string stsDiscoveryEndpoint = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration";
ConfigurationManager<OpenIdConnectConfiguration> configManager = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint);
OpenIdConnectConfiguration config = configManager.GetConfigurationAsync().Result;
TokenValidationParameters validationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ValidateIssuer = false,
IssuerSigningTokens = config.SigningTokens,
ValidateLifetime = false
};
JwtSecurityTokenHandler tokendHandler = new JwtSecurityTokenHandler();
SecurityToken jwt;
var result = tokendHandler.ValidateToken(token, validationParameters, out jwt);
return jwt as JwtSecurityToken;
}
}