【问题标题】:Is there any java example of verification of JWT for aws cognito API?是否有任何验证 AWS cognito API 的 JWT 的 java 示例?
【发布时间】:2018-06-29 14:11:12
【问题描述】:

我正在使用 aws cognito 用户池,用户登录后,我在我的单页应用程序中获得了一个 id 令牌,这是预期的,然后对于每个请求,我需要在我的后端 rest API 验证 id 令牌,这在java中,aws doc没有过多地提到如何去做。

有例子吗?

困惑包括:

  1. id 令牌似乎不仅仅是一个签名的 JWT,它也是加密的,当使用 nimbus 库时,我需要为加密的 JWT 指定一个秘密,我在哪里可以得到这个秘密?我的理解是这应该来自aws,我需要下载一些东西然后放入我的jvm密钥库吗?

  2. 有一个众所周知的jwts.json可以从aws下载,长这样:

`

{
    "keys": [
        {
            "alg": "RS256",
            "e": "AQAB",
            "kid": "HFPWHdsrG5WyulOwH5dai69YTsWz2KBB1NHbAcVx7M0=",
            "kty": "RSA",
            "n": "...",
            "use": "sig"
        },
        {
            "alg": "RS256",
            "e": "AQAB",
            "kid": "kSwTdVq/qD4Ra4Q8dJqUTlvOA7eiLxezOZ3mJKI61zU=",
            "kty": "RSA",
            "n": "....",
            "use": "sig"
        }
    ]
}

`

如何理解这个,每个属性是做什么用的?是不是用户池中的每个用户都代表一个key?

  1. 是否有任何用于 aws cognito 服务验证的示例 java 代码,我可以使用 aws sdk 还是必须使用 nimbus 之类的库自己进行验证?

【问题讨论】:

    标签: java amazon-web-services jwt aws-cognito


    【解决方案1】:

    我只是为此苦苦挣扎,并认为我可以分享它。

    如果您使用 maven,请将其添加到您的 pom.xml

    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>java-jwt</artifactId>
        <version>3.3.0</version>
    </dependency>
    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>jwks-rsa</artifactId>
        <version>0.4.0</version>
    </dependency>
    

    如果你使用 gradle add

    compile 'com.auth0:jwks-rsa:0.4.0'
    compile 'com.auth0:java-jwt:3.3.0'
    

    创建一个实现 RSAKeyProvider 的类

    import com.auth0.jwk.JwkException;
    import com.auth0.jwk.JwkProvider;
    import com.auth0.jwk.JwkProviderBuilder;
    import com.auth0.jwt.interfaces.RSAKeyProvider;
    
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.security.interfaces.RSAPrivateKey;
    import java.security.interfaces.RSAPublicKey;
    
    public class AwsCognitoRSAKeyProvider implements RSAKeyProvider {
    
        private final URL aws_kid_store_url;
        private final JwkProvider provider;
    
        public AwsCognitoRSAKeyProvider(String aws_cognito_region, String aws_user_pools_id) {
            String url = String.format("https://cognito-idp.%s.amazonaws.com/%s/.well-known/jwks.json", aws_cognito_region, aws_user_pools_id);
            try {
                aws_kid_store_url = new URL(url);
            } catch (MalformedURLException e) {
                throw new RuntimeException(String.format("Invalid URL provided, URL=%s", url));
            }
            provider = new JwkProviderBuilder(aws_kid_store_url).build();
        }
    
    
        @Override
        public RSAPublicKey getPublicKeyById(String kid) {
            try {
                return (RSAPublicKey) provider.get(kid).getPublicKey();
            } catch (JwkException e) {
                throw new RuntimeException(String.format("Failed to get JWT kid=%s from aws_kid_store_url=%s", kid, aws_kid_store_url));
            }
        }
    
        @Override
        public RSAPrivateKey getPrivateKey() {
            return null;
        }
    
        @Override
        public String getPrivateKeyId() {
            return null;
        }
    }
    

    现在您可以通过

    验证您的令牌
    String aws_cognito_region = "us-east-1"; // Replace this with your aws cognito region
    String aws_user_pools_id = "us-east-1_7DEw1nt5r"; // Replace this with your aws user pools id
    RSAKeyProvider keyProvider = new AwsCognitoRSAKeyProvider(aws_cognito_region, aws_user_pools_id);
    Algorithm algorithm = Algorithm.RSA256(keyProvider);
    JWTVerifier jwtVerifier = JWT.require(algorithm)
        //.withAudience("2qm9sgg2kh21masuas88vjc9se") // Validate your apps audience if needed
        .build();
    
    String token = "eyJraWQiOiJjdE.eyJzdWIiOiI5NTMxN2E.VX819z1A1rJij2"; // Replace this with your JWT token
    jwtVerifier.verify(token);
    

    请注意,JwkProviderBuilder 将构建一个带有 LRU 缓存的 JwkProvider,该缓存缓存从 aws 密钥存储中检索到的密钥,这非常简洁!缓存规则可以通过构建器进行更改。

    [UPDATE] 将创建 JwkProvider 移至构造函数,因此缓存受到 @danieln 评论的尊重

    【讨论】:

    • 这真是太棒了,我花了好几个小时试图从不同的角度实现它。到目前为止,我发现没有一个解决方案像这个一样简单直接。奇迹般有效!非常感谢,伙计。
    • 非常感谢,终于搞定了。我必须做的两件小事是获取更新版本的 jwt 库,并确保 JWT 令牌已去除 CR LF。
    • @AndiDev 好答案!您不应该初始化一次 JwkProvider 并在 getPublicKeyById 中返回它而不是一遍又一遍地初始化它吗?
    • @danieln 好点。感觉应该在构造函数中创建 JwkProvider 提供程序。否则我猜缓存不起作用。不再使用此代码,因此我无法验证它。如果您可以验证它是否按预期工作,我可以更改答案。
    • 我验证了它,它按预期工作。
    【解决方案2】:

    至于秘密,您是指特定于 App Client 的秘密吗?这是您在创建应用程序客户端时得到的。转到 AWS 控制台和 Cognito。选择适当的用户池,单击应用程序客户端。这是秘密,但您必须确保在创建应用程序客户端时选择创建它的选项(或不使用)。否则,制作一个新的。

    【讨论】:

    【解决方案3】:

    您可以使用标准JWT library 验证令牌。此外,验证 JWT Token 还涉及几个步骤。虽然我找不到 Java 示例,但以下是一个 NodeJS 示例,它将解释验证过程。

    const jwt = require('jsonwebtoken');
    const jwtToken = "sampletoken****";
    const jwkPem = { "alg" : "RS256", "kid" : "samplekid****" }
    
    var decodedJwt = jwt.decode(jwtToken, {complete: true});
    
    //Fail if the token is not jwt
    if (!decodedJwt) {
        console.log("Not a valid JWT token");
        return;
    }
    
    //Fail if token is not from your User Pool
    if (decodedJwt.payload.iss != iss) {
        console.log("invalid issuer");
        return;
    }
    
    //Reject the jwt if it's not an 'Access Token'
    if (!(decodedJwt.payload.token_use == 'id' || 
        decodedJwt.payload.token_use == 'access')) {
        console.log("token_use is invalid");
        return;
    }
    
    //Get the kid from the token and retrieve corresponding PEM
    var kid = decodedJwt.header.kid;
    var pem = jwkPem[kid];
    if (!pem) {
        console.log("Invalid access token");
        return;
    }
    
    //Verify the signature of the JWT token to ensure it's really coming from your User Pool and that it has not expired
    jwt.verify(jwtToken, pem, { issuer: iss, maxAge: 3600000}, function(err, payload) {
      if(err) {
        console.log(err);
      } else {
        console.log("Authorization successful");
      }
    });
    

    【讨论】:

      猜你喜欢
      • 2017-03-11
      • 2018-03-07
      • 2021-10-03
      • 1970-01-01
      • 2021-06-11
      • 2022-01-26
      • 2019-04-14
      • 2020-10-27
      • 2019-11-16
      相关资源
      最近更新 更多