用自定义注解 + 拦截器实现登录鉴权

简介: 通过自定义注解 `@Login` 结合 Spring 拦截器,实现声明式登录校验。无需重复编码,自动拦截未登录请求,提升代码可维护性与安全性,适用于前后端分离架构的权限控制实践。

在 Web 应用中,我们经常需要对某些接口进行登录状态校验:  

  • 公共接口(如登录、注册)→ 无需登录;  
  • 业务接口(如查询订单、修改资料)→ 必须登录

传统做法是在每个 Controller 方法里手动判断 session 或 token,但这样代码重复、难以维护。

更好的方式是:用自定义注解 + Spring 拦截器,实现声明式鉴权。


一、定义自定义注解 @Login

import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Login {
    // 默认值为 YES,表示需要登录;设为 NO 则跳过校验
    YesOrNo value() default YesOrNo.YES;
}

配套枚举:

public enum YesOrNo {
    YES, NO
}

✅ 这样设计的好处:  

  • 大多数接口默认需登录(安全优先);  
  • 仅对少数公开接口显式标注 @Login(YesOrNo.NO)

二、实现 Spring MVC 拦截器

注意:这里使用的是 HandlerInterceptor(Spring MVC 拦截器),而非 Servlet Filter

它能直接获取到 Controller 方法的元信息(如注解),更适合做方法级鉴权。

import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, 
                             HttpServletResponse response, 
                             Object handler) throws Exception {
        
        // 只处理 Controller 方法(排除静态资源等)
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Login login = handlerMethod.getMethodAnnotation(Login.class);
        // 如果方法上有 @Login(NO),放行
        if (login != null && YesOrNo.NO.equals(login.value())) {
            return true;
        }
        // 否则:检查是否已登录
        if (!UserAuthHelper.isAuthenticated(request)) {
            // 未登录,返回 JSON 错误
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("application/json;charset=UTF-8");
            PrintWriter writer = response.getWriter();
            writer.write(JSON.toJSONString(ResultMessage.error("请先登录")));
            writer.flush();
            return false; // 中断请求
        }
        return true; // 放行
    }
}

关键点说明:

  1. HandlerMethod:可获取被调用的 Controller 方法,进而读取其上的注解;
  2. UserAuthHelper.isAuthenticated():封装了登录状态判断逻辑(如从 Session、Token、Redis 中验证用户);
  3. 返回 false:中断请求链,不再执行 Controller 方法;
  4. 统一错误格式:返回 JSON 而非跳转页面,适配前后端分离架构。

三、注册拦截器

在 Spring Boot 中配置:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**")          // 拦截所有请求
                .excludePathPatterns("/login", "/static/**", "/error"); // 排除公开路径
    }
}

💡 即使有 @Login(NO),也可以通过 excludePathPatterns 提前放行高频公开接口,提升性能。


四、在 Controller 中使用

@RestController
@RequestMapping("/api/user")
public class UserController {
    // 公开接口:无需登录
    @Login(YesOrNo.NO)
    @PostMapping("/filter")
    public ResultMessage filter(String companyId, String code) {
        // 业务逻辑
        return ResultMessage.ok("查询成功", data);
    }
    // 默认需登录(可省略 @Login)
    @GetMapping("/profile")
    public ResultMessage profile() {
        // 自动校验登录状态
        return ResultMessage.ok("获取成功", userInfo);
    }
}

✅ 优势:  

  • 无需在每个方法写 if (!login) return error;;  
  • 权限规则集中管理,修改只需调整拦截器;  
  • 语义清晰,一眼看出接口是否需要登录。

五、对比:拦截器 vs 过滤器(Filter)

特性 Filter(Servlet) HandlerInterceptor(Spring MVC)
执行时机 更早(在 DispatcherServlet 之前) 在 Spring MVC 流程中
能否获取 Controller 方法信息 ❌ 不能 ✅ 能(通过 HandlerMethod
是否支持 Spring 注入 ❌ 需手动获取 Bean ✅ 可直接注入 Service/Bean
适用场景 编码、日志、全局异常 方法级权限、参数预处理

📌 结论:做方法级注解鉴权,优先选 拦截器


六、扩展方向

  1. 角色鉴权:扩展 @Login(role = "ADMIN")
  2. 多端支持:区分 Web / App / 小程序 的 token 校验逻辑;
  3. 自动续期:在拦截器中刷新 token 有效期;
  4. 结合 Spring Security:作为轻量级替代方案,或与之互补。

总结

通过 自定义注解 + Spring 拦截器,我们实现了:

  • 声明式登录控制
  • 零侵入业务代码
  • 高可维护性与可读性

这种模式不仅适用于登录鉴权,还可用于权限、限流、审计等横切关注点,是构建整洁、健壮 Web 系统的重要实践。


相关文章
|
9月前
|
JSON 安全 fastjson
使用阿里巴巴 Fastjson 替代 Spring Boot 默认的 Jackson
本文介绍在 Spring Boot 项目中如何替换默认的 Jackson,集成阿里巴巴 Fastjson 作为 JSON 处理框架。内容涵盖 Fastjson 与 Jackson 的核心对比、依赖配置、自定义消息转换器、null 值统一处理及循环引用控制,并提供安全建议与最佳实践,助你高效、安全地使用 Fastjson。
|
9月前
|
XML Java 数据格式
Spring @Configuration 注解详解:用 Java 代码替代 XML 配置
`@Configuration` 是 Spring 实现 Java 配置的核心注解,替代传统 XML,通过 `@Bean` 注册 Bean,结合 `@Import`、`@ComponentScan` 等实现类型安全、可维护的配置方式,推动 Spring 应用现代化。
|
9月前
|
人工智能 自然语言处理 数据可视化
数字展厅升级重点推荐方案:AI数字人+智慧大屏实现低成本高互动
传统展厅升级痛点多?AI数字人+智慧大屏方案来了!无需更换硬件,低成本快速部署,支持智能问答、多语种讲解、后台一键更新内容。适配政务、企业、文旅等多场景,提升互动体验与运营效率,助力展厅迈向“可对话、会思考”的智慧新时代。
700 0
|
11月前
|
Prometheus 监控 Cloud Native
测试开发必看!JVM调优10大技巧,性能瓶颈瞬间搞定
JVM调优是提升Java应用性能、稳定性的关键手段。通过优化内存配置与GC策略,在吞吐量与停顿时间间平衡,结合压测与监控工具分析指标,持续迭代优化,助力高并发系统高效运行。
|
9月前
|
SQL 安全 Java
了解 SQL 注入:原理、危害与防御
SQL注入是Web安全头号威胁,攻击者通过恶意SQL代码窃取、篡改或删除数据。本文详解其原理、危害及防御方案,强调预编译、输入校验、最小权限等核心防护措施,助你筑牢数据库安全防线。
|
9月前
|
Java API Spring
Spring Boot 中的 @PathVariable:获取 RESTful 路径参数
在Spring Boot中,`@PathVariable`用于提取RESTful API URL中的动态参数。支持单个或多个路径变量,参数名一致时可省略value属性,不一致时需显式绑定,是构建清晰、语义化接口的关键注解之一。
|
9月前
|
JSON 前端开发 Java
Spring MVC 常见注解详解:让 HTTP 请求精准命中你的方法
本文详解Spring MVC核心注解,从@RequestMapping到@GetMapping等快捷方式,结合@PathVariable、@RequestBody等常用配套注解,助你掌握声明式路由开发,提升效率,实现RESTful风格接口设计。
|
9月前
|
Java Spring
Spring Boot 中的 @RequestParam:获取查询参数与表单数据
`@RequestParam` 用于提取 HTTP 请求中的查询参数或表单数据,支持设置参数名、是否必填及默认值。适用于 `?key=value` 形式或 POST 表单,字段多时推荐封装为实体类自动绑定,与 `@PathVariable` 按路径取值不同,用途明确,是处理 Web 请求的常用方式。
|
9月前
|
JSON 前端开发 Java
Spring Boot 中常用的 MVC 注解
Spring Boot 开发中,核心注解如 `@RestController`、`@RequestMapping`、`@PathVariable`、`@RequestParam` 和 `@RequestBody` 是构建 RESTful 接口的基础。它们分别用于定义控制器、映射请求路径、获取路径参数、查询参数及请求体数据,掌握后可高效开发 Web 接口,适用于前后端分离架构。
|
9月前
|
JSON 前端开发 Java
Spring Boot 中的 @RequestMapping 与快捷映射注解
`@RequestMapping` 是 Spring MVC 中用于映射 HTTP 请求路径与处理方法的核心注解,可标注在类或方法上。类上使用定义公共前缀,方法上指定具体路径和请求方式。常用属性包括 `value`(路径)、`method`(请求类型)、`produces`(响应类型)。Spring 还提供了 `@GetMapping`、`@PostMapping` 等快捷注解,语义更清晰,推荐优先使用。