Filter提供了一种检查和过滤进入您的应用程序的HTTP请求的便捷机制。例如,您要基于某些条件将自定义标头注入到请求/响应中,或者要在访问控制器并处理请求之前运行一些检查。
import javax.servlet.*;
@Component public class RoomsCreateFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // your code goes here.
// then you need to pass it in the chain. chain.doFilter(request, response); } }
|
- @Component 是一个注释,使我们可以在ApplicationContext中将类注册为Bean
- implements Filter 接口告诉Spring通过进行注册时应如何使用此类 @Component
- import javax.servlet.*; 导入Filter,ServletRequest,ServletResponse,FilterChain和ServletException。
- chain.doFilter(request, response);最后是必须的。因为它告诉spring如何继续处理请求。没有它,由于链条断裂,响应将是空的。
如果您验证了某些内容并且想要停止处理请求,而只返回响应。您只需修改Response对象并从Filter类中将其返回即可。
一些真实的例子和一些不同的场景,以确保您了解整个情况。
1.确保提供了API密钥并且有效
假设您正在使用提供某些内容的API。并且您要确保对您的应用程序的所有请求都具有API密钥并且该密钥有效。当然,您不想在每个控制器和方法中都进行密钥验证。
首先创建过滤器:import java.io.IOException; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Component;
@Component public class APIKeyValidatorFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; String key = req.getHeader("X-API-KEY"); if(key == null) { ((HttpServletResponse) response).setStatus(401); response.getOutputStream().write("API Key is missing!".getBytes()); return; }
if(!KeyValidator.valid(key)) { ((HttpServletResponse) response).setStatus(403); response.getOutputStream().write("API Key is invalid".getBytes()); return; }
chain.doFilter(request, response); } }
|
做一些检查:如果未提供密钥,则显示密钥丢失错误消息。如果提供但无效,则我们显示密钥是无效消息。
2.Ratelimit一些端点
假设您要保护POST /comment端点。因此您的用户一分钟内提交的评论不得超过2条。同样,它可以在控制器中完成,但这并不是最佳选择。
让我们创建Filter类:
import javax.servlet.Filter; import java.io.IOException; import javax.servlet.*; import javax.servlet.http.HttpServletResponse;
public class PostCommentRateLimit implements Filter { RateLimiter rateLimiter;
public PostCommentRateLimit(RateLimiter rateLimiter) { this.rateLimiter = rateLimiter; }
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { int userId = 1; // Get User boolean valid = rateLimiter.validate(String.format("ratelimit.user.comments:%d", userId), 2); if(!valid) { ((HttpServletResponse) response).setStatus(429); response.getOutputStream().write("Too Many Requests".getBytes()); return; }
chain.doFilter(request, response); } }
|
- 在这里没有使用@Component。因为我们只想将过滤器应用于POST /comment端点。因此我们接下来将自己注册。
- 我们有RateLimiter构造函数。而且您不必担心。使用适合您需求的任何库。
我们将创建另一个类以所需的方式注册过滤器:import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Configuration public class RequestsFilterRegister {
@Autowired RateLimiter rateLimiter;
@Bean public FilterRegistrationBean<PostCommentRateLimit> registerPostCommentsRateLimiter(){ FilterRegistrationBean<PostCommentRateLimit> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new PostCommentRateLimit(rateLimiter)); registrationBean.addUrlPatterns("/comment");
return registrationBean; } }
|
- 我们创建RequestsFilterRegister作为@Configuration类
- registerPostCommentsRateLimiter唯一需要方法是注册过滤器。
- 使用addUrlPatterns应用过滤器作用于/comment端点。
现在我们有一个小问题。过滤器将应用于/commentGET或POST上以外的任何方法。并解决此问题,PostCommentRateLimit@doFilter如果方法未发布,我们只需修改即可跳过: HttpServletRequest req = (HttpServletRequest) request; if (!req.getMethod().equals("POST")) { chain.doFilter(request, response); return; }
|