00004.springboot java cognito

2023-10-16  本文已影响0人  笑着字太黑

java解析AWS cognito的token_油奈。的博客-CSDN博客

springboot集成JWT 登录验证_maven包 com.auth0.jwt.jwt-CSDN博客

https://fintan.jp/page/340/

https://qiita.com/akym03/items/c6e5a5d51e9a5a574f8b

<dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>4.4.0</version>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>jwks-rsa</artifactId>
            <version>0.9.0</version>
        </dependency>
package com.ibm.jp.awag.common.auth;


import java.net.MalformedURLException;
import java.net.URL;
import java.security.interfaces.RSAPublicKey;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;

import com.auth0.jwk.GuavaCachedJwkProvider;
import com.auth0.jwk.Jwk;
import com.auth0.jwk.JwkException;
import com.auth0.jwk.UrlJwkProvider;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;

public class JwtTokenUtils {
    
    private static final String AWS_REGION = "ap-northeast-1";
    private static final String AWS_COGNITO_USER_POOL_ID = "ap-northeast-1_XXXX";

    private static JWTVerifier verifier = null;
    private static long verifierExpire = -1;
    private static final long VERIFIER_LIVE_MILISEC = 10 * 60 * 1000; //10分
    private static final JWT JWT = new JWT();

    /**
     * コンストラクタ
     */
    public JwtTokenUtils() {
    }

    /**
     * IDトークン を検証します
     *
     * @param idToken 検証対象のIDトークン
     * @return 検証に成功した場合は ID Tokenのペイロード
     *
     * @throws Exception ID Tokenの値が不正なので認証に失敗した
     */
    public DecodedJWT verify(String idToken) throws Exception {
        DecodedJWT decodedToken = JWT.decodeJwt(idToken);

        // cognitoのユーザプールで署名された事を確認する
        String iss = decodedToken.getIssuer();
        if (!jwtTokenIssuer().equals(iss)) {
            throw new Exception("ID トークンの発行者が対象のシステムではありません。iss=" + iss + "idToken="+idToken);
        }

        //  ID トークンの用途が「ID」であることを確認します。
        String tokenUse = decodedToken.getClaim("token_use").asString();
        if (!"id".equals(tokenUse)) {
            throw new Exception("ID トークンの用途が ID ではありません。token_use=" + tokenUse + "idToken="+idToken);
        }

        // 署名のアルゴリズムを確認します。
        String alg = decodedToken.getAlgorithm();
        if (!"RS256".equals(decodedToken.getAlgorithm())) {
            throw new Exception("ID トークンの署名アルゴリズムが対応していないものです。alg =" + alg + "idToken="+idToken);
        }

        // payloadと署名を検証します。
        DecodedJWT decodedJWT = null;
        if ((decodedJWT = tokenVerify(decodedToken)) == null) {
            throw new Exception("ID Tokenの検証に失敗しました。" + "idToken="+idToken);
        }
        Claim userClaim = decodedJWT.getClaim("cognito:username");
        String user = userClaim.asString();
        Claim subClaim = decodedJWT.getClaim("sub");
        String sub = subClaim.asString();
        return decodedJWT;
    }

    /**
     * auth0の のライブラリを利用して 検証を行う
     *
     * @param kid ID トークンのヘッダーにある キーID
     * @return nullでなければ デコードされた ID トークン
     *
     * @throws Exception 検証に失敗した
     */
    private DecodedJWT tokenVerify(DecodedJWT jwToken) throws Exception {

        try {
            DecodedJWT verified = getVerifier(jwToken.getKeyId()).verify(jwToken);
            return verified;
        } catch (Exception e) {
            throw new Exception(e);
        }
    }

    /**
     * JWTVerifier のインスタンスを取得する。
     *
     * <p>
     * JWTVerifier は ver.3 からスレッドセーフになったので再利用する。
     * ただし、署名に使われた RSAキーペアが更新される可能性を考えて、定期的に更新する
     * </p>
     *
     * @param kid 署名に使われたキーID
     *
     * @return
     *
     * @throws MalformedURLException
     * @throws JwkException
     */
    private JWTVerifier getVerifier(String kid) throws MalformedURLException, JwkException {
        if (verifier != null && System.currentTimeMillis() < verifierExpire) {
            // 有効期限内ならそのまま使う
            return verifier;
        }
        synchronized (JWT) {
            // ロックを獲得したので念のためにもう一度確認してからインスタンスを生成する
            if (verifier != null && System.currentTimeMillis() < verifierExpire) {
                return verifier;
            }

            UrlJwkProvider http = new UrlJwkProvider(new URL(jwksUrl()));
            GuavaCachedJwkProvider provider = new GuavaCachedJwkProvider(http);
            Jwk jwk = provider.get(kid);

            Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null);
            verifier = JWT.require(algorithm)
                    .withIssuer(jwtTokenIssuer())
                    .build();

            // JWTVerifier の寿命を延ばす
            verifierExpire = System.currentTimeMillis() + VERIFIER_LIVE_MILISEC;

            Calendar expire = GregorianCalendar.getInstance();
            expire.setTimeInMillis(verifierExpire);
            System.out.println("JWTVerifierのインスタンスを生成しました。期限は"
                    + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(expire.getTime()));

        }

        return verifier;

    }

    /**
     * ID トークンの発行者を取得します
     *
     * @return
     */
    private String jwtTokenIssuer() {
        return String.format("https://cognito-idp.%s.amazonaws.com/%s", AWS_REGION, AWS_COGNITO_USER_POOL_ID);
    }

    /**
     * JSON Web トークン (JWT) セットのURLを取得します。
     *
     * @return
     */
    private String jwksUrl() {
        return jwtTokenIssuer() + "/.well-known/jwks.json";
    }

}

做成cognito pool时选择用户名,然后可以取得通过cognito:username取得用户名(sub是32位的uuid)
    public static String getUserId(String idToken) {
        DecodedJWT decodedJWT = JWT.decodeJwt(idToken);
        Claim userClaim = decodedJWT.getClaim("cognito:username");
        return userClaim.asString();
    }
上一篇 下一篇

猜你喜欢

热点阅读