Un client authentifié avec AWS Amplify Authentication (https://aws-amplify.github.io/docs/js/authentication) envoie un id_token au serveur et valide l'id_token sur un serveur implémenté en Java.
TL;DR
IdTokenValidator.java
package com.exampleawsCognito.jwt;
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.DecodedJWT;
/**
 *Gérer les jetons d'identification obtenus en s'authentifiant avec Cognito
 *
 * <p>
 *Source référencée pour la mise en œuvre
 * https://github.com/awslabs/cognito-proxy-rest-service/blob/master/src/main/kotlin/com/budilov/cognito/services/CognitoService.kt
 * </p>
 *
 * @ThreadSafe
 *
 */
public class IdTokenValidator {
	private static final String AWS_REGION = "ap-northeast-1";
	private static final String AWS_COGNITO_USER_POOL_ID = "my_userpool_id";
	private static JWTVerifier verifier = null;
	private static long verifierExpire = -1;
	private static final long VERIFIER_LIVE_MILISEC = 10 * 60 * 1000; //10 minutes
	private static final JWT JWT = new JWT();
	/**
	 *constructeur
	 */
	public IdTokenValidator() {
	}
	/**
	 *Valider le jeton d'identification
	 *
	 * @Param ID Jeton IDToken à vérifier
	 * @Charge utile du jeton d'identification si la validation de retour est réussie
	 *
	 * @jette InvalidTokenException L'authentification a échoué car la valeur du jeton d'ID n'est pas valide
	 */
	public DecodedJWT verify(String idToken) throws InvalidTokenException {
		DecodedJWT decodedToken = JWT.decodeJwt(idToken);
		//Assurez-vous qu'il est connecté au pool d'utilisateurs cognito
		String iss = decodedToken.getIssuer();
		if (!jwtTokenIssuer().equals(iss)) {
			throw new InvalidTokenException("L'émetteur du jeton d'identification n'est pas le système cible. Iss=" + iss, idToken);
		}
		//Assurez-vous que le jeton d'identification est utilisé pour "ID".
		String tokenUse = decodedToken.getClaim("token_use").asString();
		if (!"id".equals(tokenUse)) {
			throw new InvalidTokenException("Le but du jeton ID n'est pas ID. jeton_use=" + tokenUse, idToken);
		}
		//Vérifiez l'algorithme de signature.
		String alg = decodedToken.getAlgorithm();
		if (!"RS256".equals(decodedToken.getAlgorithm())) {
			throw new InvalidTokenException("L'algorithme de signature de jeton d'identification ne le prend pas en charge. alg=" + alg, idToken);
		}
		//Validez la charge utile et la signature.
		DecodedJWT decodedJWT = null;
		if ((decodedJWT = tokenVerify(decodedToken)) == null) {
			throw new InvalidTokenException("La vérification du jeton d'identité a échoué.", idToken);
		}
		return decodedJWT;
	}
	/**
	 *Effectuer la vérification à l'aide de la bibliothèque d'auth0
	 *
	 * @param kid ID ID de clé dans l'en-tête du jeton
	 * @Si return n'est pas nul, le jeton d'ID décodé
	 *
	 * @jette InvalidTokenException La validation a échoué
	 */
	private DecodedJWT tokenVerify(DecodedJWT jwToken) throws InvalidTokenException {
		try {
			DecodedJWT verified = getVerifier(jwToken.getKeyId()).verify(jwToken);
			return verified;
		} catch (Exception e) {
			throw new InvalidTokenException(e);
		}
	}
	/**
	 *Obtenez une instance de JWTVerifier.
	 *
	 * <p>
	 *JWTVerifier est ver.Puisqu'il est devenu thread-safe à partir de 3, il sera réutilisé.
	 *Cependant, il doit être mis à jour régulièrement, étant donné que la paire de clés RSA utilisée pour la signature peut être mise à jour.
	 * </p>
	 *
	 * @ID de clé param kid utilisé pour la signature
	 *
	 * @return
	 *
	 * @throws MalformedURLException
	 * @throws JwkException
	 */
	private JWTVerifier getVerifier(String kid) throws MalformedURLException, JwkException {
		if (verifier != null && System.currentTimeMillis() < verifierExpire) {
			//S'il est dans la date d'expiration, utilisez-le tel quel
			return verifier;
		}
		synchronized (JWT) {
			//J'ai le verrou, alors vérifiez-le à nouveau au cas où puis créez l'instance
			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();
			//Prolongez la vie de JWTVerifier
			verifierExpire = System.currentTimeMillis() + VERIFIER_LIVE_MILISEC;
			Calendar expire = GregorianCalendar.getInstance();
			expire.setTimeInMillis(verifierExpire);
			Logger.info("Création d'une instance de JWTVerifier. Date limite"
					+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(expire.getTime()));
		}
		return verifier;
	}
	/**
	 *Obtenez l'émetteur du jeton d'identification
	 *
	 * @return
	 */
	private String jwtTokenIssuer() {
		return String.format("https://cognito-idp.%s.amazonaws.com/%s", AWS_REGION, AWS_COGNITO_USER_POOL_ID);
	}
	/**
	 *Jeton Web JSON(JWT)Obtenez l'URL de l'ensemble.
	 *
	 * @return
	 */
	private String jwksUrl() {
		return jwtTokenIssuer() + "/.well-known/jwks.json";
	}
}
InvalidTokenException.class
public class InvalidTokenException extends Exception {
    public InvalidTokenException(String message, String idToken) {
        super(message + " token is " + idToken);
    }
    public InvalidTokenException(Throwable e) {
        super(e);
    }
}
Côté utilisateur
    try{
        //TODO IdTokenValidator est thread-safe, alors rendez-le statique
        DecodedJWT payload = new IdTokenValidator().verify(idToken);
        String cognitoUserName = payload.getClaim("cognito:username").asString();
        //Traitement requis
    }catch (InvalidTokenException e) {
        Logger.error("La vérification du jeton d'identité a échoué", e);
        badRequest("La valeur de IdToken n'est pas valide");
    }
Recommended Posts