是否有任何用于aws cognito API的JWT验证的Java示例?

2022-09-01 22:34:34

我正在使用aws cognito用户池,用户登录后,我在我的单页应用程序上得到了一个id令牌,这是预期的,然后对于每个请求,我需要在我的后端休息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. 是否有任何用于aws cognito服务验证的示例Java代码,我可以使用aws sdk还是必须使用nimbus等库自行进行验证?

答案 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>

如果您使用渐变添加

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

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