Valider le jeton d'ID d'un utilisateur authentifié par AWS Cognito en Java

Chose que tu veux faire

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

la mise en oeuvre

IdTokenValidator.java

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.java

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");
    }

référence

Recommended Posts

Valider le jeton d'ID d'un utilisateur authentifié par AWS Cognito en Java
Comment obtenir l'ID d'un utilisateur qui s'est authentifié avec Firebase dans Swift
Mesurer la taille d'un dossier avec Java
Une explication rapide des cinq types de statique Java
Trouvez le nombre de jours dans un mois avec Kotlin
Examiner la liste des polices disponibles dans AWS Lambda + Java
Une histoire sur l'utilisation de l'API League Of Legends avec JAVA
Créons une application TODO en Java 5 Changer l'affichage de TODO
Représentez graphiquement les informations du capteur de Raspberry Pi en Java et vérifiez-les avec un navigateur Web
Augmenter dynamiquement le nombre d'éléments dans un tableau bidimensionnel Java (tableau multidimensionnel)
Obtenez le résultat de POST en Java
Obtenir une liste de fichiers S3 avec ListObjectsV2Request (AWS SDK for Java)
L'histoire de l'oubli de fermer un fichier en Java et de l'échec
L'histoire de la création d'un lanceur de jeu avec une fonction de chargement automatique [Java]
Exprimons le résultat de l'analyse du code d'octet Java dans un diagramme de classes
L'identité des paramètres de rails [: id]
Exemple de programme qui renvoie la valeur de hachage d'un fichier en Java
Diviser une chaîne avec ". (Dot)" en Java
Comment obtenir le chemin absolu d'un répertoire s'exécutant en Java
L'histoire de l'écriture de Java dans Emacs
Faisons une application de calculatrice avec Java ~ Créez une zone d'affichage dans la fenêtre
Jusqu'à ce que vous exécutiez un programme Java avec le SDK AWS local sur Windows
Code pour supprimer tous les fichiers du préfixe spécifié dans AWS S3 (Java)
L'histoire de la comparaison de chaînes de bas niveau en Java
[Java] Gestion des Java Beans dans la chaîne de méthodes
L'histoire de la fabrication d'un Othello ordinaire à Java
Lire une chaîne dans un fichier PDF avec Java
Créer un CSR avec des informations étendues en Java
À propos de l'idée des classes anonymes en Java
Une histoire sur le JDK à l'ère de Java 11
L'histoire de l'apprentissage de Java dans la première programmation
Ressentez le passage du temps même à Java
Calculer le score de similarité des chaînes de caractères avec JAVA
Importer des fichiers de la même hiérarchie en Java
Il y a plus d'une douzaine d'années, un utilisateur de Java a tenté d'étudier les fonctions de Java8 (Generics).
[Java] Informations entières des caractères du fichier texte acquises par la méthode read ()
Comment enregistrer des fichiers avec l'extension spécifiée sous le répertoire spécifié en Java dans la liste
Ecrire un test en mettant en œuvre l'histoire de M. Nabeats dans le monde avec du rubis
Configurer des cookies signés (pour CloudFront) avec des stratégies personnalisées à l'aide du kit AWS SDK pour Java
[Java] Découpez une partie de la chaîne de caractères avec Matcher et des expressions régulières
Résumé de l'utilisation du jeu de proxy dans IE lors de la connexion avec Java
Soumettre une tâche à AWS Batch avec Java (Eclipse)
CI l'architecture des applications Java / Kotlin avec ArchUnit
Un examen rapide de Java appris en classe part4
L'histoire de la création d'un proxy inverse avec ProxyServlet
Surveillez l'état interne des programmes Java avec Kubernetes
Vérifiez le comportement de Java Intrinsic Locks avec bpftrace
Remarque sur l'initialisation des champs dans le didacticiel Java
[Java] Récupère le fichier dans le fichier jar quel que soit l'environnement
Implémentez rapidement singleton avec enum en Java
[Java] Lors de l'écriture du source ... Mémorandum ①
Sortie true avec if (a == 1 && a == 2 && a == 3) en Java (identifiant invisible)
Un examen rapide de Java appris en classe part3
Un examen rapide de Java appris en classe part2
Modifier la qualité de stockage des images JPEG en Java
Une vue d'ensemble du framework Java natif de Kubernetes Quarkus
L'histoire de la création de DTO, semblable à Dao avec Java, SQLite
Récapitulez les éléments supplémentaires de la classe Optional dans Java 9