Implementing Login Authentication with Custom Annotations and Interceptors in Spring Boot
This guide demonstrates how to enforce login authentication in a Spring Boot application by defining a @LoginUser annotation, creating a corresponding interceptor, registering it in the MVC configuration, and testing the functionality with sample controller endpoints, illustrating session handling and thread‑local user storage.
This article explains how to protect Spring Boot controller methods that require a logged‑in user by using a custom @LoginUser annotation together with a request interceptor.
1. Define the annotation
package com.futao.springmvcdemo.annotation;
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LoginUser {
/**
* Required user role (default is Normal)
*/
Role role() default Role.Normal;
}2. Implement the interceptor
package com.futao.springmvcdemo.annotation.impl;
import com.futao.springmvcdemo.model.enums.Role;
import com.futao.springmvcdemo.model.system.ErrorMessage;
import com.futao.springmvcdemo.model.system.RestResult;
import com.futao.springmvcdemo.utils.ThreadLocalUtils;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.*;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.annotation.Resource;
import javax.servlet.http.*;
@Component
public class LoginUserInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = LoggerFactory.getLogger(LoginUserInterceptor.class);
@Resource
private ThreadLocalUtils
threadLocalUtils;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod hm = (HandlerMethod) handler;
LoginUser methodAnno = hm.getMethodAnnotation(LoginUser.class);
LoginUser classAnno = hm.getBeanType().getAnnotation(LoginUser.class);
if (ObjectUtils.anyNotNull(methodAnno, classAnno)) {
HttpSession session = request.getSession(false);
if (ObjectUtils.allNotNull(session)) {
String loginUser = (String) session.getAttribute(SystemConfig.LOGIN_USER_SESSION_KEY);
if (ObjectUtils.allNotNull(loginUser)) {
System.out.println("当前登陆用户为:" + loginUser);
threadLocalUtils.set(loginUser);
return true;
} else {
System.out.println("用户不存在");
}
} else {
RestResult restResult = new RestResult(false, "-1", ErrorMessage.NOT_LOGIN, ErrorMessage.NOT_LOGIN.substring(6));
response.getWriter().append(JSON.toJSONString(restResult));
return false;
}
}
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// release thread‑local resource
threadLocalUtils.remove();
}
}3. Register the interceptor in MVC configuration
package com.futao.springmvcdemo.annotation;
import com.futao.springmvcdemo.annotation.impl.*;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.web.servlet.config.annotation.*;
import javax.annotation.Resource;
@SpringBootConfiguration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Resource
private SignInterceptor signInterceptor;
@Resource
private LoginUserInterceptor loginUserInterceptor;
@Resource
private RequestLogInterceptor requestLogInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(requestLogInterceptor).addPathPatterns("/**");
registry.addInterceptor(loginUserInterceptor).addPathPatterns("/**");
registry.addInterceptor(signInterceptor).addPathPatterns("/**");
}
}4. Sample controller
package com.futao.springmvcdemo.controller;
import com.futao.springmvcdemo.annotation.LoginUser;
import com.futao.springmvcdemo.service.UserService;
import com.alibaba.fastjson.JSONObject;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.UUID;
@RequestMapping(path = "User", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@RestController
public class UserController {
@Resource
private UserService userService;
@LoginUser
@GetMapping(path = "my")
public JSONObject my() {
JSONObject json = new JSONObject();
json.put("当前的登陆的用户是:", userService.currentUser());
return json;
}
@PostMapping(path = "login")
public JSONObject login(@RequestParam("mobile") String mobile, HttpServletRequest request) {
HttpSession session = request.getSession();
session.setAttribute(SystemConfig.LOGIN_USER_SESSION_KEY, String.valueOf(UUID.randomUUID()));
session.setMaxInactiveInterval(SystemConfig.SESSION_INVALIDATE_SECOND);
return new JSONObject();
}
}The login endpoint creates an HttpSession , stores a random UUID as the user identifier, and writes the session ID to the browser as a JSESSIONID cookie. Subsequent requests automatically include this cookie; the interceptor extracts the session ID, looks up the stored user key in a server‑side map, and, if valid, places the user information into a ThreadLocal for easy access throughout the request processing.
Beyond authentication, the same annotation‑driven interceptor pattern can be extended to implement features such as third‑party request signing, system logging, or role‑based access control without modifying each controller method.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
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.