Versiones comparadas

Clave

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

...

Bloque de código
languagejava
themeEclipse
titleFiltro de autorización
linenumberstrue
@Component
public class JwtAuthorizationFilter extends OncePerRequestFilter {

	private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager
			.getLogger( JwtAuthorizationFilter.class );   

	@Autowired
	private JwtTokenUtil jwtTokenUtil;

	//   @Override
	protected void doFilterInternal( HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
			FilterChain filterChain ) throws ServletException, IOException {

		if ( isPrivate( httpServletRequest ) ) {

			final String token = httpServletRequest.getHeader( AUTHORIZATION_HEADER );
			
			// INCLUIR AQUÍ LAS COMPROBACIONES NECESARIAS DE LA APLICACIÓN
			// Con getClaim sólo se comprueba si el token es correcto
			jwtTokenUtil.getClaim( token );
       }

		filterChain.doFilter( httpServletRequest, httpServletResponse );
	}

	private boolean isPrivate( HttpServletRequest httpServletRequest ) {
		final RequestMatcher privateUrl = new AntPathRequestMatcher( PRIVATE_PREFIX + "/**" );
		return privateUrl.matches( httpServletRequest );
	}
}

De aquí, lo más importante, y lo que tendremos que implementar de acuerdo a las necesidades de nuestra aplicación es el método doFilterInternal(). En éste, inicialmente se comprueba que la petición es a un método privado (las demás no se filtrarán) con la función isPrivate definida más abajo. Después va la parte personalizada, en este caso se comprueba el token y se obtiene el siva id; ambas cosas están implementadas en la llamada a getSivaIdFromToken de expedientesService, que tenemos en nuestro proyecto y hemos añadido con @Autowired, de forma que si cualquiera de los dos pasos falla, se lanzará una excepción, que es la que se devolverá al frontend y será controlada en éste. Si todo es correcto, llamamos a filterChain.doFilter(...), que sirve para continuar al siguiente filtro, si hay otros definidos.

Este filtros tendremos que añadirlo en nuestra configuración de seguridad:

Bloque de código
languagejava
themeEclipse
titleFiltros en configuración de seguridad
linenumberstrue
	/**
	 * Defino como Bean el authorization filter para que sea accedido desde los filtros ya que no estan en el mismo contexto
	 */
	@Bean
	public JwtAuthorizationFilter jwtAuthorizationFilterBean() {
		return new JwtAuthorizationFilter();
	}

	/**
	 * Proveedor de gestion de acceoss
	 */
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.sessionManagement().sessionCreationPolicy( SessionCreationPolicy.STATELESS ) // configuro politica de
		// sesion sin estado
		.and().cors() // Aniado configuracion CORS por defecto
		.and().csrf().disable()
		.addFilterBefore( jwtAuthorizationFilterBean(), BasicAuthenticationFilter.class );
	}
RUTAS A NO FILTRAR: INCLUIR RUTAS PÚBLICAS Y RUTAS DE OAUTH, PUES SE FILTRAN DIRECTAMENTE
	private List<String> skipUrls = Arrays.asList( "/public/**", "/mncs/consulta-expedientes-api/**" );
	private AntPathMatcher pathMatcher = new AntPathMatcher();

	@Override
	protected boolean shouldNotFilter( HttpServletRequest request ) throws ServletException {
		return skipUrls.stream().anyMatch( p -> pathMatcher.match( p, request.getServletPath() ) );
	}

	@Override
	protected void doFilterInternal( HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
			FilterChain filterChain ) throws ServletException, IOException {

		final String token = httpServletRequest.getHeader( HEADER_AUTHORIZATION_KEY );

  		// INCLUIR AQUÍ LAS COMPROBACIONES NECESARIAS DE LA APLICACIÓN
		// Con getClaim sólo se comprueba si el token es correcto
		try {
			jwtTokenUtil.getClaim( token );
		} catch ( ServicioException e ) {
			httpServletResponse.setStatus( e.getStatus().value() );
			return;
		}

		// OBLIGATORIO
		filterChain.doFilter( httpServletRequest, httpServletResponse );
	}
}

Este filtro lo utilizaremos como mínimo para comprobar el token POSE. Marcando la clase con @Component y extendiendo a OncePerRequestFilter, directamente se ejecutará en cada petición que se reciba.

Se deben ignorar rutas públicas y rutas con token OAuth, pues se filtran directamente, y si intentamos abrir un token OAuth con los métodos de token POSE saltará un error. Para saltarse estas rutas, tenemos en el código el array skipUrls. Aquí, tenemos que añadir la ruta base OAuth a mano, que en el ejemplo es /mncs/consulta-expedientes-api/**. Después, teniendo eso, el método shouldNotFilter se encarga de hacer match de la ruta a la que se ha llamado.

Después, si se ejecuta el filtro, se ejecuta el código que indiquemos en doFilterInternal. Aquí, como comentamos, por lo menos comprobaremos el token POSE llamando a jwtTokenUtil.getClaim, pero si por la lógica de la aplicación se necesita filtrar algo más, también se añadirá aquíComo vemos, tenemos sólo filtro de autorización, pero no tenemos filtro de autenticación. Esto se debe a que La autenticación es realizada por el Portal de Servicios en el proceso de obtención y refresco del token, por lo que no es necesario en nuestros servicios.


Constantes

En las siguientes explicaciones se utilizan algunas constantes. Para definirlas, podemos tener una clases Constants.java, en el paquete base del proyecto, por ejemplo. Esta clase, únicamente con las constantes que se utilizan en esta explicación y las cadenas para los métodos REST públicos y privados, sería la siguiente:

...