Information Security 10 min read

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.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Master Spring Security: Custom Configurations, Filters, and Advanced Features

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.

backendJavaauthenticationAuthorizationSpring SecuritySecurity Configuration
Spring Full-Stack Practical Cases
Written by

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.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.