SpringSecurity 6 custom Filter invalid solution

Background

  1. Implement custom login by overriding org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#attemptAuthentication
  2. I found that no matter how I log in, I still jump to the login page when accessing protected resources.

Solution

/**
*Add this sentence
*/
myFilter.setSecurityContextRepository(new HttpSessionSecurityContextRepository());

Reference

A little rain in Jiangnan

Complete code

package com.example.springsecuritytest;


import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.context.DelegatingSecurityContextRepository;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.AntPathMatcher;

import java.io.IOException;
import java.util.Properties;

@Configuration
public class SecurityConfig {<!-- -->


    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {<!-- -->


        /**
         * data source
         */
        InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
        UserDetails abc = User.withUsername("abc").password("{noop}123").build();
        inMemoryUserDetailsManager.createUser(abc);



        AuthenticationManagerBuilder authenticationManagerBuilder = httpSecurity.getSharedObject(AuthenticationManagerBuilder.class);
        authenticationManagerBuilder.userDetailsService(inMemoryUserDetailsManager);
        AuthenticationManager authenticationManager = authenticationManagerBuilder.build();


        MyFilter myFilter = new MyFilter();
        myFilter.setAuthenticationManager(authenticationManager);
        myFilter.setPostOnly(true);
        myFilter.setRequiresAuthenticationRequestMatcher(
                new AntPathRequestMatcher("/dologin", "POST")
        );
        myFilter.setSecurityContextRepository(new HttpSessionSecurityContextRepository());/**Important*/


        httpSecurity.authorizeHttpRequests(f ->
                f
                        .requestMatchers("/login").permitAll()
                        .requestMatchers("/vc").permitAll()
                        .requestMatchers("/dologin").permitAll()
                        .anyRequest().authenticated()
        );


        httpSecurity.formLogin(f ->
                f
                       .loginPage("/login")
                        .loginProcessingUrl("/dologin")
        );

        httpSecurity.addFilterAt(myFilter, UsernamePasswordAuthenticationFilter.class);
        httpSecurity.authenticationManager(authenticationManager);


        httpSecurity.csrf(AbstractHttpConfigurer::disable);
        return httpSecurity.build();
    }

    @Bean
    public DefaultKaptcha getDefaultKaptcha(){<!-- -->
        DefaultKaptcha captchaProducer = new DefaultKaptcha();
        Properties properties = new Properties();
        properties.setProperty("kaptcha.border", "yes");//Picture border
        properties.setProperty("kaptcha.border.color", "20,15,90");// Border color
        properties.setProperty("kaptcha.textproducer.font.color", "blue"); // Font color
        properties.setProperty("kaptcha.image.width", "110");// Image width
        properties.setProperty("kaptcha.image.height", "40");// Image height
        properties.setProperty("kaptcha.textproducer.font.size", "30");// Font size
        properties.setProperty("kaptcha.session.key", "code");// session key
        properties.setProperty("kaptcha.textproducer.char.length", "5");//Verification code length
        properties.setProperty("kaptcha.textproducer.font.names", "Song style, Kai style, Microsoft Yahei");// Font
        Config config = new Config(properties); //com.google.code.kaptcha.util.Config
        captchaProducer.setConfig(config);
        return captchaProducer;
    }

}



package com.example.springsecuritytest;


import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;

import com.google.code.kaptcha.impl.DefaultKaptcha;
@Controller
public class TestController {<!-- -->


    @Autowired
    DefaultKaptcha defaultKaptcha;

    @RequestMapping("/test")
    public String s(){<!-- -->
        return "Hello";
    }

    @RequestMapping("/index")
    public String ss(){<!-- -->
        return "index";
    }


    @RequestMapping("/login")
    public String ass(){<!-- -->
        return "login";
    }

    @RequestMapping("/vc")
    public void fasf(HttpServletRequest request, HttpServletResponse response) throws IOException {<!-- -->

        response.setDateHeader("Expires", 0);
        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        response.addHeader("Cache-Control", "post-check=0, pre-check=0");
        response.setHeader("Pragma", "no-cache");
        response.setContentType("image/jpeg"); //Corresponding format

        String text = defaultKaptcha.createText();
        BufferedImage image = defaultKaptcha.createImage(text);

        HttpSession session = request.getSession();
        session.setAttribute("vc",text);
        System.out.println(text);
        ServletOutputStream outputStream = response.getOutputStream();
        ImageIO.write(image,"jpeg",outputStream); //Tool class writes
    }


}
package com.example.springsecuritytest;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.thymeleaf.util.StringUtils;

public class MyFilter extends UsernamePasswordAuthenticationFilter {<!-- -->


    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {<!-- -->
// UsernamePasswordAuthenticationToken abc = new UsernamePasswordAuthenticationToken("abc", "123");
// setDetails(request,abc);


        if (!request.getMethod().equals("POST")) {<!-- -->
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        HttpSession session = request.getSession();
        String vc = (String) session.getAttribute("vc");

        String vc1 = request.getParameter("vc");

        if(!StringUtils.equals(vc,vc1)){<!-- -->
            System.out.println("Verification code does not match");
            throw new BadCredentialsException("Verification code does not match");
        }
        System.out.println("Verification code matches");
        return super.attemptAuthentication(request, response);


// return this.getAuthenticationManager().authenticate(abc);

// return super.attemptAuthentication(request, response);
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form class="form-signin" method="post" action="/dologin">
    <h2 class="form-signin-heading">Please sign in</h2>
    <p>
        <label for="username" class="sr-only">Username</label>
        <input type="text" id="username" name="username" class="form-control" placeholder="Username" required="" autofocus="\ ">
    </p>
    <p>
        <label for="password" class="sr-only">Password</label>
        <input type="password" id="password" name="password" class="form-control" placeholder="Password" required="">
    </p>
    <p>
        <label for="vc" class="sr-only">Password</label>
        <input type="text" id="vc" name="vc" class="form-control" placeholder="vc" required="">
    </p>
    <img src="/vc">
    <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
</body>
</html>
 <dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
\t\t