sessions multiple fixation ejemplo close spring redis spring-boot spring-security-oauth2 spring-session

multiple - spring-boot 1.3.0.RC1: ClassCastException para obtener información de usuario oauth2 de sesión persistió en Redis



spring session multiple sessions (0)

Estoy trabajando con una aplicación de arranque de primavera con inicio de sesión único OAuth2 (en desarrollo, pero ya está funcionando).

y cambié la tienda de sesiones de Tomcat a Redis.

Problema

ClassCastException cuando intento obtener mi objeto Usuario de SecurityContextHolder .

Almacenamiento del objeto User en UsernamePasswordAuthenticationToken

@Service @Transactional public class MyTokenService implements ResourceServerTokenServices { @Setter private OAuth2RestOperations restTemplate; @Autowired ResourceServerProperties sso; @Override public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException, InvalidTokenException { // get from http://some-auth-provider/me MyUser myUser = getMyInfo(); // persist to mysql UserEntity user = save(myUser); OAuth2Request request = new OAuth2Request(null, sso.getClientId(), null, true, null, null, null, null, null); // org.springframework.boot.devtools.restart.classloader.RestartClassLoader@3d66ad6e logger.info(user.getClass().getClassLoader().toString()); UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getId(), "N/A", user.getAuthorities()); token.setDetails(user); return new OAuth2Authentication(request, token); } @Override public OAuth2AccessToken readAccessToken(String accessToken) { throw new UnsupportedOperationException("Not supported: read access token"); } }

Sesión después de autenticada

127.0.0.1:6379> keys * 1) "spring:session:expirations:1445309400000" 2) "spring:session:sessions:3447d160-5f41-49c9-abf9-2bf0ef2e6bc2" 127.0.0.1:6379> hkeys spring:session:sessions:3447d160-5f41-49c9-abf9-2bf0ef2e6bc2 1) "sessionAttr:SPRING_SECURITY_SAVED_REQUEST" 2) "sessionAttr:org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN" 3) "lastAccessedTime" 4) "maxInactiveInterval" 5) "sessionAttr:SPRING_SECURITY_LAST_EXCEPTION" 6) "sessionAttr:SPRING_SECURITY_CONTEXT" 7) "creationTime" 127.0.0.1:6379> type spring:session:sessions:3447d160-5f41-49c9-abf9-2bf0ef2e6bc2:sessionAttr:SPRING_SECURITY_CONTEXT none

Retirando el objeto de usuario (después de autenticado)

public UserEntity getMyInfo() { OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) SecurityContextHolder.getContext().getAuthentication(); Long userId = (Long) oAuth2Authentication.getPrincipal(); UsernamePasswordAuthenticationToken userAuthentication = (UsernamePasswordAuthenticationToken) oAuth2Authentication.getUserAuthentication(); try { // sun.misc.Launcher$AppClassLoader@14dad5dc logger.info(userAuthentication.getDetails().getClass().getClassLoader().toString()); return (UserEntity) userAuthentication.getDetails(); } catch (Exception e) { // fixme ClassCastException // workaround return userRepository.accountDetail(userId); } }

userAuthentication objeto userAuthentication y confirmo userAuthentication.details con el objeto MyUser. entonces ClassCastException ocurre al convertir UserEntity a UserEntity, pero ¿por qué?

Puedo obtener el principal (= UserEntity.id) correctamente.

¿Alguien tiene alguna solución?

a continuación es parte de la configuración actual.

Dependencias

springBootVersion = ''1.3.0.RC1'' compile("org.springframework.boot:spring-boot-starter-redis") compile("org.springframework.session:spring-session") compile("com.github.kstyrc:embedded-redis:0.6")

Configuración de Redis

@Configuration @EnableRedisHttpSession public class RedisConfig { private static RedisServer redisServer; @Profile({"local", "unit"}) @Bean public RedisConnectionFactory connectionFactory() throws IOException { RedisExecProvider customProvider = RedisExecProvider.defaultProvider() .override(OS.MAC_OS_X, Architecture.x86_64, "/path/to/redis/3.0.2/redis-server"); redisServer = new RedisServerBuilder() .redisExecProvider(customProvider) .port(Protocol.DEFAULT_PORT) .build(); redisServer.start(); return new JedisConnectionFactory(); } @Profile({"local", "unit"}) @PreDestroy public void destroy() { if (redisServer != null) { redisServer.stop(); } } @Bean @ConditionalOnMissingBean(RequestContextFilter.class) public RequestContextFilter requestContextFilter() { return new RequestContextFilter(); } @Bean public FilterRegistrationBean requestContextFilterChainRegistration( @Qualifier("requestContextFilter") Filter securityFilter) { FilterRegistrationBean registration = new FilterRegistrationBean(securityFilter); registration.setOrder(SessionRepositoryFilter.DEFAULT_ORDER + 1); registration.setName("requestContextFilter"); return registration; }

Configuración de OAuth2 Sso

@Configuration @EnableOAuth2Sso @EnableWebSecurity public class OAuth2Config extends WebSecurityConfigurerAdapter { @Autowired ResourceServerProperties sso; @Autowired @Qualifier("userInfoRestTemplate") private OAuth2RestOperations restTemplate; @Primary @Bean public ResourceServerTokenServices userInfoTokenServices() { MyTokenService tokenService = new MyTokenService(); tokenService.setRestTemplate(restTemplate); return tokenService; } // ... }

Problema similar

OAuth2ClientContext (spring-security-oauth2) no persistió en Redis cuando se usa spring-session y spring-cloud-security

Cambio el orden de filtro (en RedisConfig.java) como respuesta anterior, pero no funciona.

Mi orden de filtro actual está debajo.

o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: ''metricFilter'' to: [/*] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: ''springSessionRepositoryFilter'' to: [/*] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: ''requestContextFilter'' to: [/*] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: ''characterEncodingFilter'' to: [/*] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: ''OAuth2ClientContextFilter'' to: [/*] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: ''springSecurityFilterChain'' to: [/*] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: ''webRequestLoggingFilter'' to: [/*] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: ''applicationContextIdFilter'' to: [/*]

Código de actualización

la causa de ClassCastException es la discrepancia de ClassLoader.

org.springframework.boot.devtools.restart.classloader.RestartClassLoader y sun.misc.Launcher$AppClassLoader

pero no tengo idea de resolver este problema, como siempre.

Resuelto

Cambio el orden de filtro a continuación y funciona.

  1. requestContextFilter
  2. oAuth2ClientContextFilter
  3. springSessionRepositoryFilter