Master Spring Security: Step‑by‑Step Authentication Flow in Spring Boot
This article walks through the Spring Security authentication flow in a Spring Boot 2.2.11 application, detailing filter execution, token creation, provider selection, custom DaoAuthenticationProvider configuration, and session management, complemented by code snippets and diagrams for each step.
Environment: Spring Boot 2.2.11.RELEASE + JPA2
Security Process Handling
The core of Spring Security is the Filter chain; the diagram below shows the execution flow.
Detailed steps:
1.1 The parent class of UsernamePasswordAuthenticationFilter is AbstractAuthenticationProcessingFilter, which first executes the doFilter method from the parent class.
1.2 The attemptAuthentication method of UsernamePasswordAuthenticationFilter is invoked.
Here a UsernamePasswordAuthenticationToken object is instantiated with the username and password for subsequent verification.
1.3 Authentication proceeds with this.getAuthenticationManager().authenticate(authRequest), using the system‑provided ProviderManager.
The crucial part is the following for‑loop that iterates over AuthenticationProviders.
It first checks whether each AuthenticationProvider supports the authentication type.
Class<? extends Authentication> toTest = authentication.getClass();The variable toTest corresponds to the class used by UsernamePasswordAuthenticationFilter.
1.4 To validate username and password we need an AuthenticationProvider that supports UsernamePasswordAuthenticationToken, such as a custom DaoAuthenticationProvider subclass.
The parent class defines the supports method:
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}Thus providing a DaoAuthenticationProvider subclass is sufficient for user verification.
1.5 Custom DaoAuthenticationProvider bean definition:
@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider daoAuthen = new DaoAuthenticationProvider();
daoAuthen.setPasswordEncoder(passwordEncoder());
daoAuthen.setUserDetailsService(userDetailsService());
daoAuthen.setHideUserNotFoundExceptions(false);
return daoAuthen;
}1.6 The for‑loop then calls: result = provider.authenticate(authentication); This invokes the authenticate method of the parent class AbstractUserDetailsAuthenticationProvider.
The retrieveUser method is implemented in the DaoAuthenticationProvider subclass.
If a UserDetails object is returned, the process proceeds to password verification.
1.7 Password verification is performed by DaoAuthenticationProvider.
The subsequent steps handle successful authentication events or unified exception handling.
Security Login Authorization Configuration
Entity class
@Entity
@Table(name = "T_USERS")
public class Users implements UserDetails, Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;
private String username;
private String password;
}DAO
public interface UsersRepository extends JpaRepository<Users, String>, JpaSpecificationExecutor<Users> {
Users findByUsernameAndPassword(String username, String password);
Users findByUsername(String username);
}Security configuration
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private UsersRepository ur;
@Resource
private LogoutSuccessHandler logoutSuccessHandler;
@Bean
public UserDetailsService userDetailsService() {
return username -> {
Users user = ur.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("用户名不存在");
}
return user;
};
}
@Bean
public PasswordEncoder passwordEncoder() {
return new PasswordEncoder() {
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return rawPassword.equals(encodedPassword);
}
@Override
public String encode(CharSequence rawPassword) {
return rawPassword.toString();
}
};
}
@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider daoAuthen = new DaoAuthenticationProvider();
daoAuthen.setPasswordEncoder(passwordEncoder());
daoAuthen.setUserDetailsService(userDetailsService());
daoAuthen.setHideUserNotFoundExceptions(false);
return daoAuthen;
}
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/pos/**").authenticated()
.and()
.formLogin()
.loginPage("/sign/login")
.and()
.logout()
.logoutSuccessHandler(logoutSuccessHandler)
.logoutUrl("/sign/logout");
http.sessionManagement()
.maximumSessions(1)
.expiredUrl("/sign/login?expired")
.sessionRegistry(sessionRegistry());
}
}Controller interfaces
@Controller
public class LoginController {
@RequestMapping("/sign/login")
public String login() {
return "login";
}
}
@RestController
@RequestMapping("/sign")
public class LogoutController {
@GetMapping("/logout")
public Object logout(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(null);
SecurityContextHolder.clearContext();
return "success";
}
}
@RestController
@RequestMapping("/pos")
public class PosController {
@GetMapping("")
public Object get() {
return "pos success";
}
}
// Get online user count
@RestController
@RequestMapping("/sessions")
public class SessionController {
@Resource
private SessionRegistry sessionRegistry;
@GetMapping("")
public Object list() {
return sessionRegistry.getAllPrincipals();
}
}Testing shows that when a user logs in from different browsers, the configured maximum concurrent session limit (1) is enforced, and subsequent logins invalidate the previous session.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
