Backend Development 8 min read

Implementing a Custom Annotation for Anonymous Access in Spring Security

This article explains how to create a custom @IgnoreAuth annotation and integrate it with Spring Security to automatically whitelist controller methods, comparing the two standard ways of permitting requests—configure(WebSecurity) for static resources and configure(HttpSecurity) for filter‑chain‑aware endpoints—while providing full source code examples.

Architecture Digest
Architecture Digest
Architecture Digest
Implementing a Custom Annotation for Anonymous Access in Spring Security

In Spring Security projects, developers often need to allow certain interfaces to be accessed anonymously, but modifying the security configuration each time is cumbersome. Spring Security provides two main strategies for permitting requests:

1. configure(WebSecurity web) – adds paths to the ignoring() list, bypassing the entire Spring Security filter chain. This is suitable for static resources such as CSS, JS, images, etc.

2. configure(HttpSecurity http) – uses .authorizeRequests().antMatchers(...).permitAll() within the filter chain, allowing the request to pass through while still enabling other security filters (e.g., authentication handling for login endpoints).

To avoid repetitive configuration, a custom annotation @IgnoreAuth can be defined and applied to controller methods that should be publicly accessible. The annotation is limited to methods annotated with @RequestMapping (or its shortcuts) so that only request‑mapping methods are considered.

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IgnoreAuth {}

A security configuration class extending WebSecurityConfigurerAdapter is then created. In its configure(WebSecurity web) method, the RequestMappingHandlerMapping bean is injected to retrieve all handler methods. Each method is inspected; if it carries the @IgnoreAuth annotation, the corresponding URL patterns are added to the ignoring() list for the appropriate HTTP method (GET, POST, DELETE, PUT).

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    @Override
    public void configure(WebSecurity web) throws Exception {
        WebSecurity and = web.ignoring().and();
        Map
handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
        handlerMethods.forEach((info, method) -> {
            if (StringUtils.isNotNull(method.getMethodAnnotation(IgnoreAuth.class))) {
                info.getMethodsCondition().getMethods().forEach(requestMethod -> {
                    switch (requestMethod) {
                        case GET:
                            info.getPatternsCondition().getPatterns().forEach(pattern -> {
                                and.ignoring().antMatchers(HttpMethod.GET, pattern);
                            });
                            break;
                        case POST:
                            info.getPatternsCondition().getPatterns().forEach(pattern -> {
                                and.ignoring().antMatchers(HttpMethod.POST, pattern);
                            });
                            break;
                        case DELETE:
                            info.getPatternsCondition().getPatterns().forEach(pattern -> {
                                and.ignoring().antMatchers(HttpMethod.DELETE, pattern);
                            });
                            break;
                        case PUT:
                            info.getPatternsCondition().getPatterns().forEach(pattern -> {
                                and.ignoring().antMatchers(HttpMethod.PUT, pattern);
                            });
                            break;
                        default:
                            break;
                    }
                });
            }
        });
    }
}

The approach leverages the internal Spring MVC infrastructure: RequestMappingHandlerMapping collects all @RequestMapping methods, AbstractHandlerMethodMapping initializes them, and detectHandlerMethods registers each handler. By scanning the resulting map, the configuration dynamically adds the annotated endpoints to the ignore list without manual edits.

Using this method, static resources can continue to be ignored via the first strategy, while endpoints that must still pass through the security filter chain (such as login URLs) remain configured with the second strategy.

Javabackend-developmentCustom AnnotationSpring SecurityWebSecurityConfigurerAdapter
Architecture Digest
Written by

Architecture Digest

Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.

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.