EDITAR:
registro de org.springframework.security:
2022-01-17 12:31:03.495 IST 2022-01-17 10:31:03.495 DEBUG [080-exec-5] osswsSessionManagementFilter - Request requested invalid session id D5F8BA31A3D7466AK3K3C8EA26A4F037 Default 2022-01-17 12:31:03.495 IST 2022-01-17 10:31:03.495 DEBUG [080-exec-5] osswaAnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext Debug 2022-01-17 12:31:03.495 IST "Request requested invalid session id D5F8BA31A3D7466AK3K3C8EA26A4F037" Debug 2022-01-17 12:31:03.495 IST "Set SecurityContextHolder to anonymous SecurityContext" Default 2022-01-17 12:31:03.494 IST 2022-01-17 10:31:03.494 DEBUG [080-exec-5] osswcSecurityContextPersistenceFilter - Set SecurityContextHolder to empty SecurityContext Debug 2022-01-17 12:31:03.494 IST "Set SecurityContextHolder to empty SecurityContext" Default 2022-01-17 12:31:03.493 IST 2022-01-17 10:31:03.493 DEBUG [080-exec-5] ossecurity.web.FilterChainProxy - Securing GET /logo192.png Debug 2022-01-17 12:31:03.493 IST "Securing GET /logo192.png"*** Pero si miro en los registros algunas solicitudes después de que puedo obtener la autenticación válida:
Depuración 2022-01-17 12:31:03.945 IST "Establecer SecurityContextHolder en SecurityContextImpl [Authentication=OAuth2AuthenticationToken [Principal=com. .security.oauth.CustomOAuth2User@ , Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress= ***, SessionId=9438C880A19C93AADJI206B9B8B3386], Autoridades otorgadas=[ROLE_USER, SCOPE_https://www.googleapis.com/auth/userinfo.email, SCOPE_https://www.googleapis.com/auth/userinfo.profile, SCOPE_openid]] ]" Depurar
2022-01-17 12:31:03.945 IST "Recuperado SecurityContextImpl [Authentication=OAuth2AuthenticationToken [Principal=com. .security.oauth.CustomOAuth2User@ , Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=*** , SessionId=9438C880A19C93AADJI206B9B8B3386], Autoridades otorgadas=[ROLE_USER, SCOPE_https://www.googleapis.com/auth/userinfo.email, SCOPE_https://www.googleapis.com/auth/userinfo.profile, SCOPE_openid]]]" Depuración
2022-01-17 12:31:03.945 IST "Recuperado SecurityContextImpl [Authentication=OAuth2AuthenticationToken [Principal=com. .security.oauth.CustomOAuth2User@ , Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=*** , SessionId=9438C880A19C93AADJI206B9B8B3386], Autoridades otorgadas=[ROLE_USER, SCOPE_https://www.googleapis.com/auth/userinfo.email, SCOPE_https://www.googleapis.com/auth/userinfo.profile, SCOPE_openid]]]" Predeterminado
2022-01-17 12:31:03.944 IST 2022-01-17 10:31:03.944 DEBUG [080-exec-8] ossecurity.web.FilterChainProxy - Protección de GET /auth/api/getBasicInfo
parece que la identificación de la sesión es inconsistente
Utilizo la opción de inicio de sesión social oauth2 incorporada de seguridad de primavera, implementé una clase OAuth2LoginSuccess con el método onAuthenticationSuccess y dentro de ella busco el usuario que corresponde a la identificación social que obtuve del oauth:
CustomOAuth2User oAuth2User = (CustomOAuth2User) authentication.getPrincipal(); int sociald = oAuth2User.getAttribute("id"); User user = usersUtils.getUserBySocailId(socialId); enter code here // add the user details to the Auth SecurityContextHolder.clearContext(); ((OAuth2AuthenticationToken) authentication).setDetails(user); SecurityContextHolder.getContext().setAuthentication(authentication);Si depuro dentro de onAuthenticationSuccess, puedo ver una autenticación válida con todos los detalles del usuario.
después del inicio de sesión, redirijo a la página de inicio y envío una solicitud de autenticación al servidor para verificar si hay un usuario conectado.
el problema es que el 50% de las veces la solicitud se completa con éxito y el usuario puede realizar solicitudes autenticadas.
pero el otro 50% me redirigen automáticamente a la página de inicio de sesión y cuando reviso el registro veo que Spring Boot dice que el usuario no está autenticado y se pierde la autenticación.
Pero en onAuthenticationSuccess siempre puedo ver la autenticación correcta.
Mi ApplicationSecurityConfig se ve así:
http.csrf().disable().authorizeRequests() .antMatchers("/login*", "/signin/**", "/signup/**", "/oauth2/**").permitAll() .antMatchers(Constants.ADMIN_PREFIX + "/**").hasRole("ADMIN") .antMatchers(Constants.AUTH_PREFIX + "/**").hasAnyRole("ADMIN", "USER") .antMatchers(Constants.PUBLIC_PREFIX + "/**").permitAll() .anyRequest().permitAll() .and() .exceptionHandling().authenticationEntryPoint(new UnauthenticatedRequestHandler()) .and() .formLogin() .passwordParameter("password") .usernameParameter("email") .loginPage("/Login") .loginProcessingUrl("/loginSecure").permitAll().successHandler(new LoginSuccess()).failureHandler(new FailureSuccess()) .and() .oauth2Login() .loginPage("/Login") .userInfoEndpoint() .userService(oAuth2UserService) .and() .successHandler(new OAuth2LoginSuccess()) .and() .rememberMe() .rememberMeParameter("remember-me") .tokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(21)) .userDetailsService(this.applicationUserService) .and() .logout() .clearAuthentication(true).invalidateHttpSession(true).logoutSuccessUrl("/login") .addLogoutHandler(new CustomLogOutHandler());Y esta es la función que compruebo si el usuario ha iniciado sesión:
@GetMapping(Constants.AUTH_PREFIX + "/checkUserLogged") public Integer checkUserLogged(Authentication authentication,HttpServletRequest request) { try{ if (authentication != null) { User (User) authentication.getDetails(); if (user == null) { return -1; } return user.getId(); } } catch (Exception e){ logger.warning(e.getLocalizedMessage()); } return -1; }pero cuando ocurre el problema, no puede ejecutar el controlador porque la seguridad de primavera devolvió un error no autorizado antes.
Gracias de antemano por su ayuda
Encontré la solución, espero que esto pueda ayudar.
Lo que me causó el problema fue que GCP y GAE usan varias instancias del servidor, y si el usuario inició sesión en una determinada instancia no significa que las otras instancias también estén familiarizadas con él porque Spring HTTPSession está en memoria.
Cambié la plataforma de sesión para usar spring-session jdbc usando la siguiente configuración en application.properties:
spring.session.store-type=jdbc-- puede usar redis en lugar de jdbc, siempre que la sesión se almacene en un lugar compartido entre todas las instancias.
también agregó el administrador de transacciones a SecurtityConfig:
@Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); }y agregó las siguientes configuraciones:
http.csrf().disable() .sessionManagement() .maximumSessions(1) .and() .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)Además, como @stringy05 mencionó que el Repositorio authrizenClient también necesita ser actualizado:
/** * Use the servlet container session store for authorized OAuth2 Clients */ @Bean public OAuth2AuthorizedClientRepository authorizedClientRepository() { return new HttpSessionOAuth2AuthorizedClientRepository(); }y agregue la línea .authorizedClientRepository a httpconfig:
.... .oauth2Login() .loginPage("/Login") .authorizedClientRepository(authorizedClientRepository) .authorizationEndpoint().and() .userInfoEndpoint() .userService(oAuth2UserService) .and() .successHandler(new OAuth2LoginSuccess())....
Con respecto a GAE, agregué la siguiente línea al archivo app.yaml:
network: session_affinity: true