Versiones comparadas

Clave

  • Se ha añadido esta línea.
  • Se ha eliminado esta línea.
  • El formato se ha cambiado.

Tabla de contenidos

...

Anteriormente utilizábamos un token generado por POSE, pero se ha cambiado a OAuth, a partir del 21/03/2022 todo va con OAuth.

Configuración

Si hemos seguido esta guía ya tendremos la configuración hecha: Configuración de proyectos Spring Boot para FundeWebJs. Debemos repasar que no nos falte ninguna dependencia o repository en el pom, las clases de configuración, que tengamos las properties que se indican, y que la clase inicial tenga la anotación correspondiente (que básicamente es como decir que se revise todo, pero es importante subrayarlo).

Token en métodos REST

Una vez configurado, las clases de nuestros servicios REST deben llevar esta anotaciónPara recibir el token en nuestro método REST, lo haremos en el header auth-token de la petición, y lo especificaremos en nuestros métodos Java con @RequestHeader, y podemos comprobarlo de la siguiente manera:

Bloque de código
languagejava
@GetMapping("/titulaciones")
public ResponseEntity<List<TitulacionDTO>> titulaciones(@RequestHeader(value="auth-token", required = true) String tokenCodificado) {
	// Comprobamos el token
	try {
		jwtTokenUtil.getClaim( tokenCodificado );
	} catch( final ServicioException e ) {
		log.error( e.getLocalizedMessage() );
		return new ResponseEntity<>( HttpStatus.FORBIDDEN );
	}
}
@RequestMapping( "${app.server.path}" )

Y para obtener el token en los métodos REST, utilizamos @AuthenticationPrincipalDentro de estos métodos tendremos que comprobar el token, devolviendo forbidden (ResponseEntity<>(HttpStatus.FORBIDDEN)) si no es correcto. Para comprobarlo, podemos utilizar la siguiente clase:

Bloque de código
languagejava
@Component
public class JwtTokenUtil {
 
	private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager
			.getLogger( JwtTokenUtil.class );
 
	@Value( "${es.um.jwt.secret}" )
	private String secret;
 
	// In minutes
	@Value( "${es.um.jwt.expires}" )
	private long expires;
 
	@Value( "${es.um.jwt.expiresImpersonation}" )
	private long expiresImpersontion;
 
	/**
	 * Get the claim from the token If token expirated throw TokenExpiredException If token is invalid throw
	 * UnauthorizedException
	 */
	public Claims getClaim( String token ) {
		try {
			final Claims claims = Jwts.parser().setSigningKey( TextCodec.BASE64.encode( secret ) )
					.parseClaimsJws( token ).getBody();
			JwtTokenUtil.log.debug( "El claims es: " + claims.toString() );
			JwtTokenUtil.log.debug( "El subject es: " + claims.getSubject() );
 
			final Date expiration = claims.getExpiration();
			if ( Instant.now().isAfter( expiration.toInstant() ) ) {
				JwtTokenUtil.log.error( "Expiration Date: " + expiration.toString() );
				JwtTokenUtil.log.error( "Current Instant: " + Instant.now().toString() );
				JwtTokenUtil.log.error( "Error el token " + token + " está caducado" );
				throw new TokenExpiredException();
			}
 
			return claims;
 
		} catch ( final JwtException e ) {
			JwtTokenUtil.log.error( "Error filtering:" + e );
			throw new UnauthorizedException();
		}
	}
}

Como vemos, tiene que ir anotada con @Component, y después la instanciaremos en nuestro controlador REST con @Autowired. También vemos que cogemos el valor del secret y de cuándo expira de nuestro application.properties. Podemos ver cómo funciona la parametrización en esta página de la wiki.

El secret lo utilizamos para decodificar el token, y obtenemos un objeto de tipo Claims. Podemos ver la información que contiene con toString(), pero lo más importante es obtener el email del usuario logeado, que lo haremos con .getSubject().

Si el token no es válido, o si ha expirado, se lanza una excepción. Para ello nos hemos definido excepciones propias, en un paquete exceptions. Las clases correspondientes son las siguientes:

ServicioException.java

Bloque de código
languagejava
/**
 * ServicioNotFoundException
 */
public class ServicioException extends RuntimeException {
 
	private static final long serialVersionUID = 1L;
 
	private static final HttpStatus status = HttpStatus.BAD_REQUEST;
 
	protected ServicioException( String msg ) {
		super( msg );
	}
 
	public HttpStatus getStatus() {
		return ServicioException.status;
	}
 
}

Token ExpiredException.java

Bloque de código
languagejava
/**
 * ServicioNotFoundException
 */
public class TokenExpiredException extends ServicioException {
 
	private static final long serialVersionUID = 1L;
 
	private static final HttpStatus status = HttpStatus.UNAUTHORIZED;
 
	public TokenExpiredException() {
		super( "Token_expired" );
	}
 
	@Override
	public HttpStatus getStatus() {
		return TokenExpiredException.status;
	}
 
}

UnauthorizedException.java

Bloque de código
languagejava
/**
 * ServicioNotFoundException
 */
public class UnauthorizedException extends ServicioException {
 
	private static final long serialVersionUID = 1L;
 
	private static final HttpStatus status = HttpStatus.UNAUTHORIZED;
 
	public UnauthorizedException() {
		super( "No tiene acceso para solicitar este servicio " );
	}
 
	@Override
	public HttpStatus getStatus() {
		return UnauthorizedException.status;
	}
 
}
@GetMapping( PRIVATE_PREFIX + API_VERSION + "/resguardos" )
public ResponseEntity getResguardos( @AuthenticationPrincipal Jwt jwt ) { ... }

Podemos obtener el identificador del token simplemente con:

Bloque de código
languagejava
jwt.getSubject()

Obtener datos del usuario a partir del token

Para esto, Recursos Humanos tiene un servicio al que podremos llamar a través de una librería: fundewebjs-serviciosrrhh-client. Esto ya lo tendremos configurado si hemos hecho correctamente el primer paso.

Para utilizarla, simplemente la incluimos con @Autowired:

Bloque de código
	@Autowired
	private ServiciosRrhhClientService serviciosRrhhClient;

Y llamamos al método getAfiliacion pasándole el subject del token y el Jwt (cogido con @AuthenticationPrincipal): 

Bloque de código
languagejava
// Versión sólo OAuth
serviciosRrhhClient.getAfiliacion(subject, jwt);

Esto nos devuelve un objeto de tipo AfiliacionDTO, que contiene información del usuario. En concreto, se compone de estos campos:

Bloque de código
languagejava
private String identificador;
private String letra;
private String tipoIdentificador;
private String nombre;
private String apellido1;
private String apellido2;
private Date fechaNacimiento;
private String sexo;
private String nacionalidad;
private DireccionDTO direccion;
private String telefonoNotificaciones;
private String emailNotificaciones;
private List<String> telefonos;
private List<String> emails;
private List<CentroAlumnoDTO> centros;

Todos tienen sus correspondientes getters. Lo más normal es que utilicemos el identificador, pero los demás también pueden ser útiles. En el caso de los emails, si un usuario tiene varios, el primero de la lista es el principal.

Se recomienda ver también la página Uso de los entornos de micampus en local, sobre la configuración de propiedades para trabajar con los entornos en localTeniendo todo esto, para comprobar el token en nuestos métodos REST sólo tendremos que llamar a .getClaim(token).