Master Spring Security: Custom Configurations, Filters, and Advanced Features
An in‑depth Spring Security guide covering custom configurations, authentication providers, user‑details services, path‑based authorization, role hierarchies, exception handling, custom filters, multiple filter chains, method security, internationalization, and session management, complete with practical code examples for Spring Boot 2.7.
1. Introduction
Spring Security is a powerful and highly customizable authentication and access‑control framework for protecting Spring‑based applications. It follows AOP principles and is implemented as a servlet filter.
Advantages
Rich functionality: comprehensive authentication mechanisms and method‑level authorization, easily extensible for custom needs.
Strong community support: active community provides abundant resources.
Integration with the Spring ecosystem: works seamlessly with Spring MVC, Spring Boot, etc.
Highly configurable: many options and extension points for tailoring to specific requirements.
This article introduces common configurations and corresponding extension points.
2. Practical Examples
2.1 Custom Configuration
Before Spring Security 5.7, custom configuration is done by extending WebSecurityConfigurerAdapter :
<code>public class SecurityConfig extends WebSecurityConfigurerAdapter {
}</code>Since 5.7, use a SecurityFilterChain bean:
<code>@Bean
public SecurityFilterChain apiSecurityFilterChain(HttpSecurity http) throws Exception {
// ...
}</code>Each defined SecurityFilterChain receives a unique HttpSecurity instance.
2.2 Custom AuthenticationProvider
<code>@Component
public class MemeryAuthticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;
Object principal = token.getPrincipal();
Object credentials = token.getCredentials();
User user = users.get(principal);
if (user == null) {
return null;
}
if (!user.getPassword().equals(credentials)) {
throw new RuntimeException("密码错误");
}
return new UsernamePasswordAuthenticationToken(principal, credentials, user.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
}</code>This custom provider implements your own verification logic.
2.3 Custom UserDetailsService and PasswordEncoder
<code>@Bean
public UserDetailsService userDetailsService() {
return new UserDetailsService() {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return users.get(username);
}
};
}
@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();
}
};
}</code>2.4 Intercept Specific Paths
<code>@Bean
public SecurityFilterChain apiSecurityFilterChain(HttpSecurity http) throws Exception {
http.csrf().disable();
http.requestMatcher(new AntPathRequestMatcher("/api/**"));
// ...
return http.build();
}</code>2.5 Path‑Based Authorization
<code>@Bean
public SecurityFilterChain apiSecurityFilterChain(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeHttpRequests()
.requestMatchers(new AntPathRequestMatcher("/api/save")).hasAnyRole("C")
.requestMatchers(new AntPathRequestMatcher("/api/find")).hasAuthority("ROLE_U");
return http.build();
}</code>2.6 Custom Authorization Decision
<code>http.authorizeHttpRequests(registry -> {
registry.antMatchers("/api/{id}").access(new AuthorizationManager<RequestAuthorizationContext>() {
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication,
RequestAuthorizationContext object) {
Map<String, String> variables = object.getVariables();
return new AuthorityAuthorizationDecision(
variables.get("id").equals("666"),
Arrays.asList(new SimpleGrantedAuthority("D"))
);
}
});
});</code>2.7 Custom Exception Handling
<code>http.exceptionHandling(customizer -> {
customizer.accessDeniedHandler(new AccessDeniedHandler() {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException ex) throws IOException, ServletException {
Map<String, Object> errors = new HashMap<>();
response.setContentType("application/json;charset=utf-8");
errors.put("code", -1);
errors.put("status", response.getStatus());
errors.put("message", ex.getMessage());
errors.put("details", ExceptionUtils.getMessage(ex));
response.getWriter().println(new ObjectMapper().writeValueAsString(errors));
}
});
});</code>2.8 Role Hierarchy
<code>@Bean
public RoleHierarchy hierarchyVoter() {
RoleHierarchyImpl hierarchy = new RoleHierarchyImpl();
hierarchy.setHierarchy("ROLE_ADMIN > ROLE_MANAGER");
return hierarchy;
}</code>2.9 Custom Logout Logic
<code>http.logout()
.logoutUrl("/logout")
.addLogoutHandler(new LogoutHandler() {
@Override
public void logout(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) {
System.out.println("退出登录");
}
})
.logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("<h2>退出登录成功</h2>");
out.close();
}
});</code>2.10 Custom Authentication Failure Handler
<code>http.formLogin()
.failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException {
response.setContentType("application/json;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("{\"code\": -1, \"message\": \"" + getRootCause(exception).getMessage() + "\"}");
out.close();
}
});</code>2.11 Adding Custom Filters
<code>@Bean
public PackAuthenticationFilter packAuthenticationFilter() {
return new PackAuthenticationFilter();
}
http.addFilterBefore(packAuthenticationFilter(), RequestCacheAwareFilter.class);
</code>2.12 Multiple Filter Chains
<code>@Bean
public SecurityFilterChain apiSecurityFilterChain(HttpSecurity http) throws Exception {
http.requestMatcher(new AntPathRequestMatcher("/api/**"));
return http.build();
}
@Bean
public SecurityFilterChain adminSecurityFilterChain(HttpSecurity http) throws Exception {
http.requestMatcher(new AntPathRequestMatcher("/admin/**"));
return http.build();
}</code>2.13 Global Method Security
<code>@Configuration
@EnableGlobalMethodSecurity(jsr250Enabled = true, prePostEnabled = true, securedEnabled = true)
public class SecurityConfig {}
// Example usage
@GetMapping("/find")
@PreAuthorize("hasRole('GUEST')")
public Object find(HttpServletResponse response) throws Exception {
return "find method invoke...";
}</code>2.14 Internationalization Support
<code>@Bean
public ReloadableResourceBundleMessageSource messageSource() {
ReloadableResourceBundleMessageSource source = new ReloadableResourceBundleMessageSource();
source.addBasenames("classpath:org/springframework/security/messages",
"classpath:messages/messages");
return source;
}</code>2.15 Prevent Duplicate Login
<code>http.sessionManagement()
.maximumSessions(1)
.expiredSessionStrategy(new SessionInformationExpiredStrategy() {
@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
HttpServletResponse response = event.getResponse();
response.setContentType("application/json;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("{\"code\": -1, \"message\": \"会话已过期,或重复登录\"}");
out.close();
}
});</code>Note: Your UserDetails implementation must override equals and hashCode .
Summary: The above configurations and features are frequently used in real‑world development. Spring Security provides a rich set of security capabilities to protect your application. With these examples you can quickly start securing your Spring Boot application.
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.