spring security + form login + redis session storage -> keep coming out anonymous User

20 Views Asked by At

I have been struggling for days because after logging in and receiving the welcome message, the user appears as an anonymous user when moving to another browser page. I confirmed that sessions are stored inside Redis. However, I keep getting errors indicating that something other than the SecurityContext is being stored in HttpSessionSecurityContextRepository.

Also It shows that a LinkedHashMap is stored inside the SpringSecurityContextHolder.

I've also tried searching on Google, but I couldn't find the answer I'm looking for. I'm not sure what the cause is.

// build.gradle
'org.springframework.boot' version '3.1.1'
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation group: 'org.springframework.security', name: 'spring-security-test'

this is the session stored in redis

{
  "creationTime": 1711475749704,
  "lastAccessedTime": 1711475904642,
  "maxInactiveInterval": 1800,
  "sessionAttr": {
    "SPRING_SECURITY_CONTEXT": {
      "authentication": {
        "authorities": [
          {
            "authority": "ROLE_ADMIN"
          }
        ],
        "details": {
          "remoteAddress": "0:0:0:0:0:0:0:1",
          "sessionId": "96f82b5f-49ee-4518-9f3a-da58f6212f7b"
        },
        "authenticated": true,
        "principal": {
          "password": null,
          "username": "[email protected]",
          "authorities": [
            {
              "authority": "ROLE_ADMIN"
            }
          ],
          "accountNonExpired": true,
          "accountNonLocked": true,
          "credentialsNonExpired": true,
          "enabled": true
        },
        "credentials": null,
        "name": "[email protected]"
      }
    },
    "SPRING_SECURITY_SAVED_REQUEST": {
      "cookies": [
        {
          "name": "Idea-571775cc",
          "value": "4869c9df-2414-4603-b718-76027a1adc42",
          "attributes": {
            "Max-Age": "-1",
            "Secure": "false"
          },
          "version": 0,
          "path": null,
          "domain": null,
          "maxAge": -1,
          "comment": null,
          "secure": false,
          "httpOnly": false
        },
        {
          "name": "SESSION",
          "value": "YTYwZTlmMGUtZDA2YS00YTBlLTgxZTYtYzg0ZjlmYjZmNzdi",
          "attributes": {
            "Max-Age": "-1",
            "Secure": "false"
          },
          "version": 0,
          "path": null,
          "domain": null,
          "maxAge": -1,
          "comment": null,
          "secure": false,
          "httpOnly": false
        }
      ],
      "locales": [
        "ko_KR",
        "ko",
        "en_US",
        "en"
      ],
      "contextPath": "",
      "method": "GET",
      "pathInfo": null,
      "queryString": null,
      "requestURI": "/error",
      "requestURL": "http://localhost:8080/error",
      "scheme": "http",
      "serverName": "localhost",
      "servletPath": "/error",
      "serverPort": 8080,
      "parameterMap": {},
      "headerNames": [
        "accept",
        "accept-encoding",
        "accept-language",
        "connection",
        "cookie",
        "host",
        "sec-ch-ua",
        "sec-ch-ua-mobile",
        "sec-ch-ua-platform",
        "sec-fetch-dest",
        "sec-fetch-mode",
        "sec-fetch-site",
        "sec-fetch-user",
        "upgrade-insecure-requests",
        "user-agent"
      ],
      "parameterNames": [],
      "redirectUrl": "http://localhost:8080/error?continue"
    }
  }
}

  1. When attempting to log in, the log shows that authentication was successful. success login security log

  2. When retrieving the authenticated user, the log indicates the process. can't not found authenticated user

20240327 10:34:08.466 [http-nio-8080-exec-5] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class org.springframework.security.core.context.SecurityContext (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; org.springframework.security.core.context.SecurityContext is in unnamed module of loader 'app')] with root cause 
java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class org.springframework.security.core.context.SecurityContext (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; org.springframework.security.core.context.SecurityContext is in unnamed module of loader 'app')

I've been continuously modifying the SecurityConfig and trying to apply filters, but I'm still not sure what the problem is.

@RequiredArgsConstructor
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final UserDetailsService userDetailsService;
    private final AuthenticationSuccessHandler customAuthenticationSuccessHandler;
    private final AuthenticationFailureHandler customAuthenticationFailureHandler;
    private final AccessDeniedHandler customAccessDeniedHandler;
    private static final String LOGIN_URL = "/api/v1/members/login";

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .csrf(AbstractHttpConfigurer::disable)
                .headers(headerConfig ->
                        headerConfig.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)
                )
                .authorizeHttpRequests(authorizeRequests ->
                        authorizeRequests
                                .requestMatchers(
                                        PathRequest.toStaticResources().atCommonLocations()
                                ).permitAll()
                                .requestMatchers(
                                        "/",
                                        "/api/v1/members/signup",
                                        "/main",
                                        "/api/v1/sse/**",
                                        "/api/v1/event/**")
                                .permitAll()
                                .requestMatchers(
                                        "/member").hasAnyRole("USER")
                                .requestMatchers("/admin").hasAnyRole("ADMIN")
                                .anyRequest().authenticated()
                );

        http
                .formLogin(form -> form
                        .loginProcessingUrl(LOGIN_URL)
                        .defaultSuccessUrl("/api/v1/")
                        .usernameParameter("email")
                        .passwordParameter("password")
                        .successHandler(customAuthenticationSuccessHandler)
                        .failureHandler(customAuthenticationFailureHandler)
                        .permitAll()
                );
        http
                .logout(logout -> logout
                        .logoutUrl("/api/v1/members/logout")
                        .logoutSuccessUrl(LOGIN_URL)
                        .invalidateHttpSession(true)
                        .deleteCookies("SESSIONID")
                );
        http
                .exceptionHandling(exceptionHandling -> exceptionHandling
                        .accessDeniedHandler(customAccessDeniedHandler)
                );
        http.
                rememberMe(rememberMe -> rememberMe
                        .rememberMeCookieName("remember")
                        .tokenValiditySeconds(3600)
                        .userDetailsService(userDetailsService)
                );
        http
                .sessionManagement(sessionManagement -> sessionManagement
                        .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                        .maximumSessions(1)
                        .maxSessionsPreventsLogin(false)
                        .expiredUrl(LOGIN_URL)
                )
                .securityContext((securityContext) -> {
                   securityContext.securityContextRepository(delegatingSecurityContextRepository());
                    securityContext.requireExplicitSave(true);
                });
        return http.build();
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncryptor();
    }

    @Bean
    public DelegatingSecurityContextRepository delegatingSecurityContextRepository() {
        return new DelegatingSecurityContextRepository(
                new RequestAttributeSecurityContextRepository(),
                new HttpSessionSecurityContextRepository()
        );
    }
}
0

There are 0 best solutions below