Backend Development 13 min read

Spring Boot Login Authentication: Filters, Interceptors, AOP, ThreadLocal, and Parameter Resolver

This article presents a comprehensive Spring Boot tutorial on implementing non‑intrusive login authentication using three techniques—Filter, Interceptor, and AOP with custom annotations—plus extensions such as ThreadLocal storage and a Spring MVC argument resolver, complete with project setup, Maven dependencies, and test screenshots.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Spring Boot Login Authentication: Filters, Interceptors, AOP, ThreadLocal, and Parameter Resolver

1. Login Authentication Overview

In modern front‑back end projects, authentication is often performed by issuing a token after a successful login, which the client sends via cookie or header on each request. The backend validates the token before executing business logic, keeping authentication logic separate from business code.

2. Non‑Intrusive Implementation Methods

Spring provides three ways to achieve non‑intrusive login and permission checks:

Java Web Filter

Spring MVC Interceptor

Spring AOP combined with a custom annotation

3. Project Structure and Prerequisites

The sample project contains a UserController with three endpoints: login, query users, and a test endpoint. After a successful login, a UUID token is generated and stored in Redis with a 30‑minute expiration.

public class LoginFilter implements Filter {
    private final RedisTemplate
redisTemplate;
    private final LoginProperties loginProperties;
    // ... init, doFilter, returnNoLogin, destroy methods ...
}

4. Implementation Details

4.1 Filter Implementation

The LoginFilter checks the request URI against an exclusion list, retrieves the token from the request header, validates it against Redis, renews the token expiration, and returns a 401 JSON response if validation fails.

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Resource
    private LoginProperties loginProperties;
    @Bean
    public FilterRegistrationBean
loginFilterRegistration() {
        FilterRegistrationBean
registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new LoginFilter(redisTemplate, loginProperties));
        registrationBean.setName("loginFilter");
        registrationBean.addUrlPatterns(loginProperties.getFilterIncludeUrl().toArray(new String[0]));
        registrationBean.setOrder(-1);
        return registrationBean;
    }
}

4.2 Interceptor Implementation

The LoginInterception interceptor performs the same token validation logic in its preHandle method and returns a 401 response when necessary.

@Component
public class LoginInterception implements HandlerInterceptor {
    @Resource
    private RedisTemplate
redisTemplate;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader(Constant.TOKEN_HEADER_NAME);
        // token validation logic ...
        return true;
    }
    // ... returnNoLogin method ...
}

4.3 AOP + Custom Annotation

A custom annotation @LoginValidator marks methods or classes that require login validation. The LoginAspect defines a pointcut for this annotation and performs token validation before proceeding.

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LoginValidator {
    boolean validated() default true;
}

@Aspect
@Component
public class LoginAspect {
    @Pointcut("@annotation(xyz.hlh.annotition.LoginValidator) || @within(xyz.hlh.annotition.LoginValidator)")
    public void pointCut() {}
    @Around("pointCut()")
    public Object before(ProceedingJoinPoint joinpoint) throws Throwable {
        // token validation logic ...
        return joinpoint.proceed();
    }
}

5. Extensions

5.1 ThreadLocal Storage

A LoginUserThread class holds the authenticated User object in a ThreadLocal , allowing downstream code to access the user without passing it explicitly.

public class LoginUserThread {
    private static final ThreadLocal
LOGIN_USER = new ThreadLocal<>();
    public static User get() { return LOGIN_USER.get(); }
    public void put(User user) { LOGIN_USER.set(user); }
    public void remove() { LOGIN_USER.remove(); }
}

5.2 Spring MVC Parameter Resolver

A custom annotation @LoginUser and a corresponding LoginUserResolver allow controller methods to receive the logged‑in User directly as a method argument.

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LoginUser {}

@Component
public class LoginUserResolver implements HandlerMethodArgumentResolver {
    @Resource
    private RedisTemplate
redisTemplate;
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(LoginUser.class);
    }
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token = request.getHeader(Constant.TOKEN_HEADER_NAME);
        return token != null ? redisTemplate.opsForValue().get(Constant.REDIS_USER_PREFIX + token) : null;
    }
}

6. Execution Order

If all three mechanisms (Filter, Interceptor, AOP) are present, the processing order is: Filter → Interceptor → AOP.

7. Maven Dependencies (pom.xml excerpt)

org.springframework.boot
spring-boot-dependencies
2.5.2
pom
import
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-aop
org.springframework.boot
spring-boot-starter-data-redis
org.projectlombok
lombok

8. Testing

Postman is used to test the login endpoint, user list retrieval, and access control. Screenshots demonstrate 401 responses for unauthenticated requests and successful responses after login.

Overall, the article provides a step‑by‑step guide to building a reusable, non‑intrusive authentication layer in Spring Boot, covering configuration, code implementation, extensions, and verification.

aopSpring BootInterceptorThreadLocalfilterLogin AuthenticationParameter Resolver
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

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.