在Spring Boot应用开发中,Filter和Interceptor是两个重要的机制,它们用于请求的预处理和后处理,广泛应用于安全、日志记录、性能监控及其他功能的实现中。本文将对此进行深入探讨,并通过登录校验的例子来演示如何使用Filter、Interceptor和JWT令牌。
Filter与Interceptor的区别
- Filter:
- 源于Servlet规范,主要用于对请求和响应进行过滤。
- 在请求到达Servlet之前和响应返回给客户端之后执行。
-
适用于统一处理某些特征的请求,例如权限认证、日志记录、压缩等。
-
Interceptor:
- Spring框架提供的功能,主要用于对Controller方法的调用进行拦截。
- 仅在Spring MVC中有效,无法对所有请求作出响应。
- 更适合处理Spring特有的逻辑,例如视图解析、方法调用前后处理等。
登录校验示例
在本示例中,我们将通过Filter实现JWT令牌的验证,同时使用Interceptor进行登录状态的检查。
1. 添加依赖
在pom.xml
中添加相关依赖(例如Spring Boot Starter Web和JWT库):
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
</dependencies>
2. 创建JWT工具类
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
public class JwtUtil {
private static final String SECRET_KEY = "your_secret_key";
public static String createToken(String username) {
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
JwtBuilder builder = Jwts.builder()
.setSubject(username)
.setIssuedAt(now)
.setExpiration(new Date(nowMillis + 3600000)) // 1小时过期
.signWith(SignatureAlgorithm.HS256, SECRET_KEY);
return builder.compact();
}
public static Claims validateToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
}
}
3. 创建Filter
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class JwtFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String token = httpRequest.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
token = token.substring(7); // 移除“Bearer ”部分
try {
Claims claims = JwtUtil.validateToken(token);
// TODO: 可以设置用户信息到上下文中
System.out.println("用户: " + claims.getSubject());
} catch (Exception e) {
throw new ServletException("无效的令牌.");
}
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
4. 注册Filter
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<JwtFilter> jwtFilter() {
FilterRegistrationBean<JwtFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new JwtFilter());
registrationBean.addUrlPatterns("/api/*"); // 过滤器应用于特定路径
return registrationBean;
}
}
5. 创建Interceptor
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// TODO: 检查用户是否登录
boolean isLoggedIn = true; // 此处可用实际逻辑判断
if (!isLoggedIn) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
return true;
}
}
6. 注册Interceptor
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor).addPathPatterns("/api/**");
}
}
总结
通过以上示例,我们展示了如何在Spring Boot应用中结合使用Filter和Interceptor来实现JWT令牌的验证和登录校验。Filter负责对每个请求的JWT进行验证,而Interceptor则是用来检查用户的登录状态。这种结合使得极大增强了应用的安全性,同时保持代码的清晰和结构化。