es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Cómo obtengo un JwtAuthenticationToken para mi HandlerMethodArgumentResolver a partir del encabezado Authorization de la solicitud?

Tengo una aplicación Spring Boot que requiere un JwtAuthenticationToken que se pase en una cabecera HTTP Authorization. La cabecera en sí proporciona un token de portador; Spring está haciendo algo de magia de la que actualmente no soy consciente para convertir esa cadena de token de portador en un JwtAuthenticationToken. Tengo algún código que extrae el ID de usuario del token, que se usa para localizar los recursos correctos en el servidor.

private String getUidFromToken(JwtAuthenticationToken token) {
  // este es un código de marcador de posición para demostrar lo que estoy haciendo con el token
}

<p>public ResponseEntity<String> getUserProfile(JwtAuthenticationToken token) {
  String uid = getUidFromToken(token);
  // resto del código
}

Dado que necesito estos tokens en un par de lugares diferentes, decidí investigar la posibilidad de mover el código getUidFromToken a un HandlerMethodArgumentResolver. El problema que tengo es que necesito un JwtAuthenticationToken, pero solo recibo el token de portador de la cabecera Authorization como una cadena.

¿Es posible que obtenga ese JwtAuthenticationToken en lugar de una cadena?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Desafortunadamente, no es posible obtener directamente un JwtAuthenticationToken desde el encabezado de autorización HTTP. El framework Spring maneja esta conversión automáticamente detrás de escena a través de su clase JwtAuthenticationTokenFilter, que se encarga de decodificar el token portador y configurar el contexto de autenticación.

    Sin embargo, podrías obtener un resultado similar creando un HandlerInterceptor personalizado en lugar de un HandlerMethodArgumentResolver. Este interceptor interceptaría la solicitud antes de que llegue al controlador, extraería el token portador del encabezado, lo pasaría por el mismo proceso de decodificación que en JwtAuthenticationTokenFilter, y luego crearía un nuevo objeto JwtAuthenticationToken para pasar a tu método del controlador.

    Aquí tienes un ejemplo de cómo podría ser el interceptor:

    public class JwtTokenInterceptor extends HandlerInterceptorAdapter {
      @Override
      public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String authorizationHeader = request.getHeader("Authorization");
        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
          String token = authorizationHeader.substring(7);
          Jwt jwt = JwtHelper.decode(token); // decodifica el token usando el mismo decodificador que en JwtAuthenticationTokenFilter
          Claims claims = new Jackson2JsonParser().parseMap(jwt.getClaims());
          List<grantedauthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(claims.get("authorities", String.class)); // extrae cualquier autoridad del token si es necesario
          JwtAuthenticationToken authenticationToken = new JwtAuthenticationToken(claims.getSubject(), authorities);
          // opcionalmente, agrega información adicional al token de autenticación basada en los reclamos
          SecurityContextHolder.getContext().setAuthentication(authenticationToken); // establece el contexto de autenticación para que las funciones de seguridad de Spring reconozcan al usuario
          return true;
        } else {
          response.setStatus(HttpStatus.UNAUTHORIZED.value());
          return false; // la solicitud no pasa la autenticación
        }
      }
    }
    

    Necesitarías registrar este interceptor en la configuración de tu aplicación para que entre en vigencia:

    @Configuration
    public class AppConfig extends WebMvcConfigurerAdapter {
      @Override
      public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new JwtTokenInterceptor());
      }
    }
    

    Con esto en su lugar, deberías poder modificar el método del controlador para tomar un parámetro HttpServletRequest:

    public ResponseEntity<string> getUserProfile(HttpServletRequest request) {
      JwtAuthenticationToken token = (JwtAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
      String uid = getUidFromToken(token);
      // resto del código
    }
    

    Ten en cuenta que puedes obtener el objeto JwtAuthenticationToken del contexto de seguridad de esta manera porque lo establecimos en el interceptor usando SecurityContextHolder. Esto también significa que cualquier otra función relacionada con la seguridad que uses (como las anotaciones @PreAuthorize) seguirá funcionando según lo esperado.

Comments are closed.