Problemas Comunes y Soluciones en OAuth con Spring Security

Error de Decodificación JSON en BaseClientDetails

Al trabajar con OAuth, es posible encounters el siguiente error:


2019-12-03 22:18:37.239  WARN 19120 --- [nio-8100-exec-4] o.s.s.o.p.c.JdbcClientDetailsService     : Could not decode JSON for additional information: BaseClientDetails [clientId=c1, clientSecret=$2a$10$NlBC84MVb7F95EXYTXwLneXgCca6/GipyWR5NHm8K0203bSQMLpvm, scope=[ROLE_ADMIN, ROLE_USER, ROLE_API], resourceIds=[res1], authorizedGrantTypes=[client_credentials, password, authorization_code, implicit, refresh_token], registeredRedirectUris=[http://www.baidu.com], authorities=[], accessTokenValiditySeconds=7200, refreshTokenValiditySeconds=259200, additionalInformation={}]

java.io.EOFException: No content to map to Object due to end of input
	at org.codehaus.jackson.map.ObjectMapper._initForReading(ObjectMapper.java:2775) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]
	at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2718) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]
	at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1863) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]
	at org.springframework.security.oauth2.provider.client.JdbcClientDetailsService$JacksonMapper.read(`JdbcClientDetailsService.java:309`) ~[spring-security-oauth2-2.3.4.RELEASE.jar:na]
	at org.springframework.security.oauth2.provider.client.JdbcClientDetailsService$ClientDetailsRowMapper.mapRow(JdbcClientDetailsService.java:268) [spring-security-oauth2-2.3.4.RELEASE.jar:na]
	at org.springframework.security.oauth2.provider.client.JdbcClientDetailsService$ClientDetailsRowMapper.mapRow(JdbcClientDetailsService.java:251) [spring-security-oauth2-2.3.4.RELEASE.jar:na]
	at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:94) [spring-jdbc-5.1.10.RELEASE.jar:5.1.10.RELEASE]
	at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:61) [spring-jdbc-5.1.10.RELEASE.jar:5.1.10.RELEASE]

Análisis del Problema

Este error ocurre en la clase JdbcClientDetailsService cuando se intenta decodificar información adicional del cliente OAuth. Al revisar la base de datos, se observa que el campo additional_information está vacío.

La solución es asegurarse de que este campo contenga:

  • Un valor null, o
  • Un JSON con formato válido

No debe contener cadenas vacías o representaciones textuales de null, ya que causarán errores en el proceso de decodificación.

Solución para Problemas CORS con SpringBoot2.x + SpringSecurity + OAuth2

Al implementar aplicaciones con arquitectura frontend-backend separada, es común enfrentar problemas de Cross-Origin Resource Sharing (CORS) al obtener tokens de acceso.

Configuración CORS Básica (antes de OAuth)


@Configuration
public class ConfiguracionCORS implements WebMvcConfigurer {

    @Override
    public void agregarMapeosCORS(CorsRegistry registro) {
        registro.agregarMapeo("/**")
                .origenesPermitidos("*")
                .metodosPermitidos("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
                .permitirCredenciales(true)
                .maximoEdad(3600)
                .cabecerasPermitidas("*");
    }
}

Configuración CORS para OAuth2

Después de integrar SpringSecurity con OAuth2, la configuración anterior puede no ser suficiente. Se requiere un filtro dedicado:


@Order(Ordered.MAYOR_PRECEDENCIA)
@Configuration
public class ConfiguracionCORSGlobal implements Filter {

    @Override
    public void init(FilterConfig configFiltro) {
    }

    @Override
    public void doFilter(SolicitudServlet solicitud, RespuestaServlet respuesta, CadenaFiltros cadena) 
            throws ServletException, IOException {
        HttpServletRequest peticion = (HttpServletRequest) solicitud;
        HttpServletResponse respuestaHttp = (HttpServletResponse) respuesta;
        
        respuestaHttp.setHeader("Access-Control-Allow-Origin","*");
        respuestaHttp.setHeader("Access-Control-Allow-Credentials","true");
        respuestaHttp.setHeader("Access-Control-Allow-Methods","POST,GET,OPTIONS,PUT,DELETE,PATCH,HEAD");
        respuestaHttp.setHeader("Access-Control-Allow-Max-Age","3600");
        respuestaHttp.setHeader("Access-Control-Allow-Headers","authorization,Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type");
        
        if("OPTIONS".equalsIgnoreCase(peticion.getMethod())){
            respuestaHttp.setStatus(HttpServletResponse.SC_OK);
        } else {
            cadena.doFilter(solicitud, respuesta);
        }
    }

    @Override
    public void destroy() {
    }
}

Etiquetas: OAuth Spring Security CORS SpringBoot seguridad

Publicado el 6-6 00:57