How Spring Security Authenticates Users: A Step‑by‑Step Deep Dive
This tutorial walks through Spring Security's authentication flow in a Spring Boot 2.2.11 application, detailing filter execution, token creation, provider verification, custom DaoAuthenticationProvider configuration, and session management with code examples and diagrams.
Environment: Spring Boot 2.2.11.RELEASE + JPA2
Security Process Flow
Security core is Filter; the diagram shows execution flow.
Detailed steps:
1.1 UsernamePasswordAuthenticationFilter inherits from AbstractAuthenticationProcessingFilter, first executes the parent doFilter method.
1.2 attemptAuthentication method is executed.
Here a UsernamePasswordAuthenticationToken object is instantiated with username and password for validation.
1.3 Authentication manager authenticates the request using ProviderManager.
The crucial for‑loop checks each AuthenticationProvider.
It first checks whether the AuthenticationProvider supports the authentication class.
<code>Class<? extends Authentication> toTest = authentication.getClass();</code>The toTest corresponds to the token class used by UsernamePasswordAuthenticationFilter.
1.4 Provide a DaoAuthenticationProvider subclass to handle UsernamePasswordAuthenticationToken.
The parent class defines the supports method:
<code>public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class
.isAssignableFrom(authentication));
}</code>This shows only a DaoAuthenticationProvider subclass is needed for user verification.
1.5 Custom DaoAuthenticationProvider bean definition:
<code>@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider daoAuthen = new DaoAuthenticationProvider();
daoAuthen.setPasswordEncoder(passwordEncoder());
daoAuthen.setUserDetailsService(userDetailsService());
daoAuthen.setHideUserNotFoundExceptions(false);
return daoAuthen;
}</code>1.6 The for‑loop invokes provider.authenticate(authentication).
<code>result = provider.authenticate(authentication);</code>This enters AbstractUserDetailsAuthenticationProvider.authenticate method in DaoAuthenticationProvider.
retrieveUser method is implemented in DaoAuthenticationProvider subclass.
If UserDetails is returned, the process continues.
1.7 Password verification step.
DaoAuthenticationProvider handles password checking.
After successful authentication, events are processed; exceptions are handled uniformly.
Security Login Authorization Configuration
Entity class
<code>@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;
}</code>DAO
<code>public interface UsersRepository extends JpaRepository<Users, String>, JpaSpecificationExecutor<Users> {
Users findByUsernameAndPassword(String username, String password);
Users findByUsername(String username);
}</code>Security configuration
<code>@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());
}
}</code>Controller interfaces
<code>@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";
}
}
// Interface to get online users count
@RestController
@RequestMapping("/sessions")
public class SessionController {
@Resource
private SessionRegistry sessionRegistry;
@GetMapping("")
public Object list() {
return sessionRegistry.getAllPrincipals();
}
}
</code>Testing: login with user zs in Chrome, then in 360 browser, then refresh Chrome; the session is invalidated, demonstrating the maximum concurrent login limit works.
End of tutorial.
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.