当前位置: 首页 > news >正文

登录校验---Filter过滤器

过滤器(Filter)

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

img

代码演示

步骤

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

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

@WebFilter(urlPatterns = ("/*"))
public class DemoFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("init 初始化拦截器...");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("拦截到了请求...放行前");// 放行filterChain.doFilter(servletRequest, servletResponse);System.out.println("拦截到了请求...放行后");}@Overridepublic 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

http://www.hskmm.com/?act=detail&tid=30431

相关文章:

  • 日志|Ajax
  • 环境变量 Path 配置实战指南:从“能用”到“专业”--两种配置环境变量的方法
  • 10月13日
  • Ubuntu22.04安装CH340/CH341驱动
  • 玄机蓝队靶场_应急响应_198:实战Live勒索病毒溯源排查
  • JetBrains Mono字体好看、及其它
  • STM32——UART
  • WebApi 交叉观察者- IntersectionObserver复盘
  • [KaibaMath]1009 关于||a|-|b||≤|a+b|的证明
  • AMPopTip - 优雅的iOS动画提示框库
  • 2026年深度对比值得推荐的10个在线客服系统
  • 文件名中有空格比较烦人
  • 20232421 2024-2025-1 《网络与系统攻防技术》实验一实验报告
  • 十月总结
  • 20251013 之所思 - 人生如梦
  • Markdown 基本语法
  • 简单工单系统的实现-客服系统中增加创建工单功能
  • 日总结 10
  • # 20232421 2024-2025-1 《网络与系统攻防技术》实验一实验报告
  • 20232317 2025-2026-1《网络与系统攻防技术》实验一实验报告
  • 给一个字符串数组,输出不同的部分
  • 连接 USB 设备
  • SpringBoot-day1(快速上手SpringBoot,SpringBoot简介,SpringBoot基础配置,属性配置,yaml文件) - a
  • Chroma私有化:本地部署完整方案
  • 嵌入式-C++面经2
  • PHP转Go系列 | 如何将 PHP 项目快速迁移到 Go 上?
  • 详细介绍:【OpenHarmony】用户文件服务模块架构
  • 详细介绍:全新 CloudPilot AI:嵌入 Kubernetes 的 SRE Agent,降本与韧性双提升!
  • “环境变量”是什么, 为什么要配置环境变量 --初学者
  • AI元人文:对大模型的召唤——未来哪吒