代码之家  ›  专栏  ›  技术社区  ›  Jakim

是否有针对aws cognito API的JWT验证的java示例?

  •  23
  • Jakim  · 技术社区  · 8 年前

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

    有什么例子吗?

    混淆包括:

    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"
            }
        ]
    }
    

    `

    如何理解这一点,每个属性都有什么用途?用户池中的每个用户都代表一个密钥吗?

    1. 是否有任何示例java代码用于aws cognito服务验证,我可以使用aws sdk还是必须使用nimbus之类的库来自己进行验证?
    3 回复  |  直到 8 年前
        1
  •  51
  •   AndiDev    5 年前

    我只是挣扎着想分享一下。

    如果您使用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密钥存储库检索到的密钥,这非常整洁!可以使用生成器更改缓存规则。

    [更新] 已将创建JwkProvider移动到构造函数,因此正如@danieln所评论的那样,缓存受到尊重

        2
  •  0
  •   chris2187    8 年前

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

        3
  •  -5
  •   Ashan    8 年前

    您可以使用标准验证令牌 JWT library . 此外,验证JWT令牌还涉及几个步骤。虽然我找不到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");
      }
    });