通过Interceptor以及Redis实现接口访问防刷

方式一

以下是通过Interceptor以及Redis实现接口访问防刷的Java代码示例:

首先,创建一个自定义拦截器类,实现HandlerInterceptor接口,并在preHandle方法中添加接口防刷逻辑。例如:

@Component
public class RateLimiterInterceptor implements HandlerInterceptor {
    private static final String RATE_LIMITER_KEY_PREFIX = "rate_limiter:";
    private static final int MAX_REQUESTS_PER_SECOND = 10;
    private final RedisTemplate<String, String> redisTemplate;

    @Autowired
    public RateLimiterInterceptor(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String ip = request.getRemoteAddr();
        String key = RATE_LIMITER_KEY_PREFIX + ip;
        Long count = redisTemplate.opsForValue().increment(key, 1);
        if (count == 1) {
            // Set a TTL to the key so it gets deleted after one second.
            redisTemplate.expire(key, 1, TimeUnit.SECONDS);
        }
        if (count > MAX_REQUESTS_PER_SECOND) {
            response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
            return false;
        }
        return true;
    }
}

上述代码中,我们使用了Redis作为存储桶,每个IP地址对应一个key,每一次请求就将key中的计数器加一,并设置一个过期时间为1秒钟。如果计数器超过最大请求数,则返回HTTP 429 Too Many Requests响应。

接下来,在Spring Boot应用程序中配置拦截器,例如:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    private final RateLimiterInterceptor rateLimiterInterceptor;

    @Autowired
    public WebConfig(RateLimiterInterceptor rateLimiterInterceptor) {
        this.rateLimiterInterceptor = rateLimiterInterceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(rateLimiterInterceptor);
    }
}

这样,我们就可以实现接口访问防刷功能了。每个IP地址在1秒钟内最多只能发送10个请求。如果超过限制,则返回HTTP 429响应。

方式二

以下是通过Interceptor以及Redis 自定义注解 + 反射 实现接口访问防刷的Java代码示例:

首先,创建一个自定义注解@RateLimit,并在注解中添加限制参数。例如:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {
    int limit() default 10;
    int timeout() default 1;
}

然后,在服务启动时,使用反射扫描所有带有@RateLimit注解的方法,并生成对应的拦截器和key。例如:

@Component
public class RateLimiterBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {
    private final Map<Method, String> rateLimiterMap = new HashMap<>();
    private ApplicationContext applicationContext;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Class<?> clazz = bean.getClass();
        Method[] methods = clazz.getDeclaredMethods();

        for (Method method : methods) {
            RateLimit annotation = AnnotationUtils.findAnnotation(method, RateLimit.class);
            if (annotation != null) {
                int limit = annotation.limit();
                int timeout = annotation.timeout();
                String key = "rate_limiter:" + clazz.getName() + ":" + method.getName() + ":" +
                        Arrays.toString(method.getParameterTypes());
                RedisTemplate<String, String> redisTemplate = applicationContext.getBean(RedisTemplate.class);
                RateLimiterInterceptor rateLimiterInterceptor = new RateLimiterInterceptor(redisTemplate, key, limit, timeout);

                this.rateLimiterMap.put(method, key);
                WebMvcConfigurer appConfig = (WebMvcConfigurer) applicationContext.getBean(WebMvcConfigurer.class);
                appConfig.addInterceptors(rateLimiterInterceptor);
            }
        }

        return bean;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

上述代码中,我们通过注解扫描所有带有@RateLimit注解的方法,并在应用程序启动时生成对应的拦截器和key。这里使用了RedisTemplate将key与计数器存储到Redis中。

接下来,创建一个自定义拦截器类RateLimiterInterceptor,并在preHandle方法中添加接口防刷逻辑。其中,根据之前生成的key从Redis中获取对应的计数器并进行限制。例如:

public class RateLimiterInterceptor implements HandlerInterceptor {
    private final RedisTemplate<String, String> redisTemplate;
    private final String key;
    private final int limit;
    private final int timeout;

    public RateLimiterInterceptor(RedisTemplate<String, String> redisTemplate, String key, int limit, int timeout) {
        this.redisTemplate = redisTemplate;
        this.key = key;
        this.limit = limit;
        this.timeout = timeout;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String ip = request.getRemoteAddr();
        String realKey = key + ":" + ip;
        Long count = redisTemplate.opsForValue().increment(realKey, 1);
        redisTemplate.expire(realKey, timeout, TimeUnit.SECONDS);
        if (count > limit) {
            response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
            return false;
        }
        return true;
    }
}

最后,在需要限制访问的接口方法上添加@RateLimit注解,例如:

@RestController
public class HelloController {
    @RateLimit(limit = 5, timeout = 1)
    @GetMapping("/hello")
    public String hello() {
        return "Hello World";
    }
}

这样,我们就可以实现接口访问防刷功能了。每个IP地址在1秒钟内最多只能发送5个请求。如果超过限制,则返回HTTP 429响应。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot可以通过拦截器(Interceptor)或者过滤器(Filter)来实现接口登录放行,实现免登录访问接口。 下面分别介绍两种实现方式: 1. 拦截器方式 首先创建一个拦截器类,用于拦截请求并判断用户是否已登录: ```java public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 判断用户是否已登录,如果已登录则放行 HttpSession session = request.getSession(); if (session.getAttribute("user") != null) { return true; } // 用户未登录,拦截请求 response.sendRedirect("/login"); return false; } } ``` 然后在Spring Boot配置文件中添加拦截器配置: ```java @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Autowired private LoginInterceptor loginInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { // 添加拦截器,拦截所有请求,除了登录接口和静态资源 registry.addInterceptor(loginInterceptor) .addPathPatterns("/**") .excludePathPatterns("/login", "/static/**"); } } ``` 上述配置中,`addPathPatterns("/**")`表示所有请求都被拦截,`.excludePathPatterns("/login", "/static/**")`表示排除了登录接口和静态资源不被拦截。 2. 过滤器方式 创建一个过滤器类,用于拦截请求并判断用户是否已登录: ```java public class LoginFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; // 判断用户是否已登录,如果已登录则放行 HttpSession session = req.getSession(); if (session.getAttribute("user") != null) { chain.doFilter(request, response); return; } // 用户未登录,重定向到登录页面 resp.sendRedirect("/login"); } @Override public void destroy() { } } ``` 然后在Spring Boot配置文件中添加过滤器配置: ```java @Configuration public class WebConfig { @Bean public FilterRegistrationBean<LoginFilter> loginFilterRegistration() { FilterRegistrationBean<LoginFilter> registration = new FilterRegistrationBean<>(); registration.setFilter(new LoginFilter()); registration.addUrlPatterns("/*"); registration.setName("loginFilter"); registration.setOrder(1); return registration; } } ``` 上述配置中,`registration.setFilter(new LoginFilter())`表示使用`LoginFilter`过滤器,`registration.addUrlPatterns("/*")`表示拦截所有请求,`registration.setOrder(1)`表示该过滤器的执行顺序为第一位。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值