在 Java 上验证 AWS id 令牌

Posted

技术标签:

【中文标题】在 Java 上验证 AWS id 令牌【英文标题】:Verify AWS id Token on Java 【发布时间】:2017-08-18 00:34:44 【问题描述】:

我在亚马逊使用 Cognito 对我的移动用户进行身份验证,一旦他们完成登录,Cognito 会提供一组令牌,我在后端使用 id 令牌。我已按照在您的 Web API 中使用 ID 令牌和访问令牌一节中的步骤进行操作 https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html我被困在第 6 步了。

据我所见,我从亚马逊获取模数和指数的字符串,我必须用它们构建一个 PublicKey,以验证 JWT 签名。

我不知道如何使用String中的这两个参数来构建PublicKey。

【问题讨论】:

您使用什么库来验证 JWT 令牌?贴一个亚马逊提供的数据示例 我正在使用connect2id.com/products/nimbus-jose-jwt处理jwt,token中包含的信息在docs.aws.amazon.com/cognito/latest/developerguide/…中有解释 如果您包含解决问题所需的代码或信息而不是文档链接,这将更实用。总结:AWS 为您提供了一个 JWK 密钥,您需要一个 java PublicKey 来验证 JWT。是这样吗? @pedrofb 现在问题只是理论上的,因为我不知道如何实现代码,遵循推荐的库connect2id.com/products/nimbus-jose-jwt/examples/… 我现在必须做类似 JWSVerifier 验证器 = new RSASSAVerifier((RSAPublicKey ) 公钥);但我需要建立公钥。亚马逊为我提供了编码字符串中的模数和指数,我不知道如何使用这个参数构建公钥。 【参考方案1】:

我终于找到了解决方法,在 aws 论坛https://forums.aws.amazon.com/message.jspa?messageID=728870 中有一个示例,但代码在 Kotlin 中。我只是将它移植到 java 并进行了一些测试,我终于验证了我的 JWT 签名:

byte[] decodedModulus = Base64.getUrlDecoder().decode(yourModulus);

byte[] decodedExponent = Base64.getUrlDecoder().decode(yourExponent);

BigInteger modulus = new BigInteger(1, decodedModulus);
BigInteger exponent = new BigInteger(1, decodedExponent);

RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(modulus, exponent);
KeyFactory keyFactory;

keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey) publicKey);
Boolean verify = parsedToken.verify(verifier);

希望对遇到同样问题的人有所帮助。

【讨论】:

您好,您的 parsedToken 是什么? 嗨 @AniruddhaRaje 我从以下位置获取解析的令牌:SignedJWT parsedToken = SignedJWT.parse(jwt);【参考方案2】:

我的编程方式是这样的,

    // Parse the Cognito Keys and get the key by kid
    // Key is just a class that is used for parsing JSON to POJO
    Key key = this.keyService.getKeyByKeyId(JWT.decode(token).getKeyId());

    // Use Key's N and E
    BigInteger modulus = new BigInteger(1, Base64.decodeBase64(key.getN()));
    BigInteger exponent = new BigInteger(1, Base64.decodeBase64(key.getE()));

    // Create a publick key
    PublicKey publicKey = null;
    try 
        publicKey = KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(modulus, exponent));
     catch (InvalidKeySpecException e) 
        // Throw error
     catch (NoSuchAlgorithmException e) 
        // Throw error
    

    // get an algorithm instance
    Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) publicKey, null);

    // I verify ISS field of the token to make sure it's from the Cognito source
    String iss = String.format("https://cognito-idp.%s.amazonaws.com/%s", REGION, POOL_ID);

    JWTVerifier verifier = JWT.require(algorithm)
            .withIssuer(iss)
            .withClaim("token_use", "id") // make sure you're verifying id token
            .build();

    // Verify the token
    DecodedJWT jwt = verifier.verify(token);

    // Parse various fields
    String username = jwt.getClaim("sub").asString();
    String email = jwt.getClaim("email").asString();
    String phone = jwt.getClaim("phone_number").asString();
    String[] groups = jwt.getClaim("cognito:groups").asArray(String.class);

我正在使用这个 repo 来验证和解析令牌,

    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>java-jwt</artifactId>
        <version>3.4.1</version>
    </dependency>

确保您正在导入以下内容,

    import com.auth0.jwt.JWT;
    import com.auth0.jwt.JWTVerifier;
    import com.auth0.jwt.algorithms.Algorithm;
    import com.auth0.jwt.exceptions.JWTDecodeException;
    import com.auth0.jwt.interfaces.DecodedJWT;

    import java.math.BigInteger;
    import java.security.KeyFactory;
    import java.security.NoSuchAlgorithmException;
    import java.security.PublicKey;
    import java.security.interfaces.RSAPublicKey;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.RSAPublicKeySpec;
    import org.apache.commons.codec.binary.Base64;

【讨论】:

以上是关于在 Java 上验证 AWS id 令牌的主要内容,如果未能解决你的问题,请参考以下文章

如何配置 AWS 用户 cognito 身份验证流程以在 Java sdk 后端生成身份令牌、访问令牌?

aws cognito用户获取id令牌android

为 aws cognito id 令牌生成基于角色的声明

如何缓存来自 cognito 的 ID 令牌,以便后续访问 API 网关?

我是不是需要在 Lambda 和 API 网关中验证 AWS Cognito 令牌?

AWS Cognito JWT 令牌验证