登录校验---Filter过滤器

简介: Filter是JavaWeb三大组件之一,用于拦截请求并实现登录校验、编码处理等功能。通过`doFilter()`方法实现过滤逻辑,支持配置拦截路径与过滤器链。常用于JWT令牌验证、跨域处理等场景。

过滤器(Filter)

  • 概念: Filter 过滤器,是 JavaWeb 三大组件(Servlet、Filter、Listener)之一。
  • 过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能。
  • 过滤器一般完成一些通用的操作,比如: 登录校验、统一编码处理、敏感字符处理等。

img

代码演示

步骤

自定义Filter:继承Filter并且重写其方法(主要重写doFilter()

配置Filter:配置@WebFilter(urlPatterns = ("/*"))以及拦截路径,并且在启动类添加注解@ServletComponentScan开启Servlet组件支持

@WebFilter(urlPatterns = ("/*"))
public class DemoFilter implements Filter {
   
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
   
        System.out.println("init 初始化拦截器...");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
   
        System.out.println("拦截到了请求...放行前");
        // 放行
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("拦截到了请求...放行后");

    }

    @Override
    public void destroy() {
   
        System.out.println("destroy方法执行...");
    }
}

方法介绍

init():初始化方法,Web 服务器启动,创建Filter时调用,只调用一次

doFilter():拦截到了请求,并执行该方法,可多次调用,注意关键的实现filterChain.doFilter()以及拦截前后的逻辑实现

destroy():销毁方法,服务器关闭执行,只调用一次

拦截路径设置

拦截路径 urlPatterns值 含义
拦截具体路径 /login 只有访问 /login 路径时,才会被拦截
目录拦截 /emps/* 访问/emps下的所有资源,都会被拦截
拦截所有 /* 访问所有资源,都会被拦截

过滤器链

一个web应用中,可以配置多个过滤器,这多个过滤器就形成了一个过滤器链。

执行顺序: 注解配置的Filter,优先级是按照过滤器类名(字符串A, B, C, ....)的自然排序。

img

扩展知识点(doFilter()

通过校验请求认证头(authHeader)所携带的token去校验,我在Postman中使用的是Bearer Token身份校验,Bearer Token 在请求头中以 Bearer 关键字加上令牌本身的形式发送,格式通常为Authorization: Bearer <token>。详细可看Apifox--什么是Bearer Token

img

代码展示 --- doFilter()

@Override
public void doFilter(ServletRequest request, ServletResponse response, 
                     FilterChain chain) throws IOException, ServletException {
   

    HttpServletRequest httpRequest = (HttpServletRequest) request;
    HttpServletResponse httpResponse = (HttpServletResponse) response;

    // 设置响应头
    setupResponseHeaders(httpResponse);

    // 处理预检请求
    if ("OPTIONS".equalsIgnoreCase(httpRequest.getMethod())) {
   
        httpResponse.setStatus(HttpServletResponse.SC_OK);
        return;
    }

    // 获取请求路径
    String requestPath = httpRequest.getRequestURI();
    String contextPath = httpRequest.getContextPath();
    String path = requestPath.substring(contextPath.length());

    // 检查是否为排除路径
    if (isExcludePath(path)) {
   
        chain.doFilter(request, response);
        return;
    }

    // 获取认证头部
    String authHeader = httpRequest.getHeader(AUTH_HEADER);

    // 检查认证头是否存在且格式正确
    if (authHeader == null || !authHeader.startsWith(BEARER_PREFIX)) {
   
        sendUnauthorizedResponse(httpResponse, "请先登录");
        return;
    }

    // 提取 JWT 令牌
    String jwtToken = authHeader.substring(BEARER_PREFIX.length()).trim();

    try {
   
        // 验证 JWT 令牌
        if (!JwtUtils.validateToken(jwtToken)) {
   
            sendUnauthorizedResponse(httpResponse, "令牌无效或已过期");
            return;
        }

        // 从 JWT 中解析用户信息
        Long userId = JwtUtils.getUserIdFromToken(jwtToken);
        String userAccount = JwtUtils.getUserAccountFromToken(jwtToken);
        String userName = JwtUtils.getUserNameFromToken(jwtToken);

        // 将用户信息放入请求属性,供后续使用
        httpRequest.setAttribute("id", userId);
        httpRequest.setAttribute("userAccount", userAccount);
        httpRequest.setAttribute("userName", userName);

        System.out.println("JWT认证成功 - 用户ID: " + userId + ", 账号: " + userAccount);

        // 继续过滤器链
        chain.doFilter(request, response);

    } catch (Exception e) {
   
        sendUnauthorizedResponse(httpResponse, "令牌解析失败: " + e.getMessage());
    }
}

封装方法

在执行过滤器中,除了校验令牌,我们还要做其他的工作

1)排除不需要认证的路径

检查是否为排除路径(不需要认证的路径):比如登录、注册等等

// 排除认证的路径
private static final String[] EXCLUDE_PATHS = {
   
    "/user/login",
    "/user/register",
    "/doc.html",
    "/webjars/",
    "/swagger-resources",
    "/v2/api-docs"
};
/**
     * 检查是否为排除路径(不需要认证的路径)
     */
private boolean isExcludePath(String path) {
   
for (String excludePath : EXCLUDE_PATHS) {
   
    if (path.startsWith(excludePath)) {
   
        return true;
    }
}
return false;

2)设置响应头

主要处理CORS(跨域资源共享)配置和字符编码

/**
     * 设置响应头
     */
private void setupResponseHeaders(HttpServletResponse response) {
   
    response.setHeader("Access-Control-Allow-Origin", "*");
    response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
    response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Requested-With");
    response.setHeader("Access-Control-Max-Age", "3600");
    response.setCharacterEncoding("UTF-8");
    response.setContentType("application/json;charset=UTF-8");
}

作用:

Access-Control-Allow-Origin: "*"

  • 允许所有域名访问你的 API
  • 如果是生产环境,建议改为具体域名:"http://your-frontend.com"

Access-Control-Allow-Methods: "GET, POST, PUT, DELETE, OPTIONS"

  • 允许前端使用这些 HTTP 方法

Access-Control-Allow-Headers: "Authorization, Content-Type, X-Requested-With"

  • 允许前端发送这些自定义请求头
  • 特别重要:包含了 Authorization,这样前端才能发送 JWT Token

Access-Control-Max-Age: "3600"

  • 预检请求缓存时间(1小时),减少重复的 OPTIONS 请求

什么是 OPTIONS 请求

OPTIONS 是 HTTP 方法之一,用于获取目标资源支持的通信选项。在 CORS 中,浏览器会自动发送 OPTIONS请求来检查是否允许跨域访问。

什么时候会发送 OPTIONS 请求

触发条件

跨域请求(域名、端口、协议不同)

非简单请求(满足以下任一条件):

简单请求(不会触发 OPTIONS):

GET /api/data HTTP/1.1
Host: api.example.com
Origin: https://frontend.com

非简单请求(会触发 OPTIONS):
自定义请求头

POST /api/user HTTP/1.1
Host: localhost:8080
Origin: http://localhost:3000
Authorization: Bearer token123  # 自定义头
X-Custom-Header: value         # 自定义头

非简单 Content-Type

POST /api/user HTTP/1.1
Content-Type: application/json  # 非简单 Content-Type

非简单 HTTP 方法

PUT /api/user/1 HTTP/1.1
PATCH /api/user/1 HTTP/1.1
DELETE /api/user/1 HTTP/1.1

3)发送未认证错误响应

/**
     * 发送未认证错误响应
     */
private void sendUnauthorizedResponse(HttpServletResponse response, String message) throws IOException {
   
    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    String jsonResponse = String.format(
        "{\"code\": 401, \"message\": \"%s\", \"data\": null, \"description\": \"未授权访问\"}",
        message
    );
    response.getWriter().write(jsonResponse);
}

end

相关文章
|
2月前
|
网络协议 开发工具 iOS开发
企业微信iPad协议:实例生命周期与零验证码恢复的技术细节
企业微信iPad协议将设备抽象为可编程实例(Guid),通过HTTP通道统一管理创建、登录、恢复与销毁。毫秒级响应替代官方15秒轮询,支持代理复用、零验证码重登、自动保活及资源回收。单节点可承载600并发,P99延迟18ms,适用于高并发群控与会话存档场景。
182 6
|
2月前
|
存储 人工智能 NoSQL
AI大模型应用实践 八:如何通过RAG数据库实现大模型的私有化定制与优化
RAG技术通过融合外部知识库与大模型,实现知识动态更新与私有化定制,解决大模型知识固化、幻觉及数据安全难题。本文详解RAG原理、数据库选型(向量库、图库、知识图谱、混合架构)及应用场景,助力企业高效构建安全、可解释的智能系统。
|
Java 容器
如何在SpringBoot项目中使用过滤器和拦截器
过滤器和拦截器是日常开发中常用技术,用于对特定请求进行增强处理,如插入自定义代码以实现特定功能。过滤器在请求到达 `servlet` 前执行,而拦截器在请求到达 `servlet` 后执行。`SpringBoot` 中的拦截器依赖于 `SpringBoot` 容器,过滤器则由 `servlet` 提供。通过实现 `Filter` 接口并重写 `doFilter()` 方法可实现过滤器;通过实现 `HandlerInterceptor` 接口并重写相应方法可实现拦截器。两者的主要区别在于执行时机的不同,需根据具体场景选择使用。
767 4
如何在SpringBoot项目中使用过滤器和拦截器
|
2月前
|
数据采集 监控 API
告别手动埋点!Android 无侵入式数据采集方案深度解析
传统的Android应用监控方案需要开发者在代码中手动添加埋点,不仅侵入性强、工作量大,还难以维护。本文深入探讨了基于字节码插桩技术的无侵入式数据采集方案,通过Gradle插件 + AGP API + ASM的技术组合,实现对应用性能、用户行为、网络请求等全方位监控,真正做到零侵入、易集成、高稳定。
470 34
|
2月前
|
人工智能 监控 Java
构建定时 Agent,基于 Spring AI Alibaba 实现自主运行的人机协同智能 Agent
借助 Spring AI Alibaba 框架,开发者可快速实现定制化自动定时运行的 Agent,构建数据采集、智能分析到人工参与决策的全流程AI业务应用。
725 45
|
2月前
|
人工智能 安全 Java
分布式 Multi Agent 安全高可用探索与实践
在人工智能加速发展的今天,AI Agent 正在成为推动“人工智能+”战略落地的核心引擎。无论是技术趋势还是政策导向,都预示着一场深刻的变革正在发生。如果你也在探索 Agent 的应用场景,欢迎关注 AgentScope 项目,或尝试使用阿里云 MSE + Higress + Nacos 构建属于你的 AI 原生应用。一起,走进智能体的新世界。
509 41
|
2月前
|
人工智能 监控 Java
零代码改造 + 全链路追踪!Spring AI 最新可观测性详细解读
Spring AI Alibaba 通过集成 OpenTelemetry 实现可观测性,支持框架原生和无侵入探针两种方式。原生方案依赖 Micrometer 自动埋点,适用于快速接入;无侵入探针基于 LoongSuite 商业版,无需修改代码即可采集标准 OTLP 数据,解决了原生方案扩展性差、调用链易断链等问题。未来将开源无侵入探针方案,整合至 AgentScope Studio,并进一步增强多 Agent 场景下的观测能力。
1459 33
|
2月前
|
人工智能 安全 API
近期 AI 领域的新发布所带来的启示
2024 年以来,AI 基础设施的快速发展过程中,PaaS 层的 AI 网关是变化最明显的基建之一。从传统网关的静态规则和简单路由开始,网关的作用被不断拉伸。用户通过使用网关来实现多模型的流量调度、智能路由、Agent 和 MCP 服务管理、AI 治理等,试图让系统更灵活、更可控、更可用。国庆期间 AI 界发布/升级了一些产品,我们在此做一个简报,从中窥探下对 AI 网关演进新方向的启示。
369 30
|
2月前
|
存储 人工智能 安全
揭秘 MCP Streamable HTTP 协议亲和性的技术内幕
函数计算推出MCP Streamable HTTP亲和机制,支持会话级请求绑定,解决传统Serverless对会话应用支持不足的问题。实现高效生命周期控制,并支持Bearer认证,助力开发者构建更稳定、安全、高性能的AI应用服务。
547 25
|
2月前
|
人工智能 搜索推荐 算法
用AI提示词搞定基金定投:技术人的理财工具实践
本文将AI提示词工程应用于基金定投,为技术人打造一套系统化、可执行的理财方案。通过结构化指令,AI可生成个性化定投策略,覆盖目标设定、资产配置、风险控制与动态调整,帮助用户降低决策门槛,规避情绪干扰,实现科学理财。
582 13