How to Prevent IP Abuse with Spring Boot Interceptor and Redis Distributed Lock

Learn how to secure a Spring Boot service by limiting request frequency per IP and URL using a custom interceptor combined with Redis distributed locks, automatically blocking abusive IPs after a configurable number of hits within a set time window.

Java High-Performance Architecture
Java High-Performance Architecture
Java High-Performance Architecture
How to Prevent IP Abuse with Spring Boot Interceptor and Redis Distributed Lock
In real projects, service security must be considered; once deployed online, services can face malicious requests and brute‑force attacks. This tutorial shows how to use an interceptor and Redis to limit the number of accesses per URL‑IP combination within a time window and block the IP accordingly.

The example assumes a Spring Boot project is already set up.

Core Interceptor Code

First, create a custom interceptor class, which contains the main logic:

/** 
 * @package: com.technicalinterest.group.interceptor
 * @className: IpUrlLimitInterceptor
 * @description: Interceptor for limiting repeated IP+URL requests
 */
@Slf4j
public class IpUrlLimitInterceptor implements HandlerInterceptor {

    private RedisUtil getRedisUtil() {
        return SpringContextUtil.getBean(RedisUtil.class);
    }

    private static final String LOCK_IP_URL_KEY = "lock_ip_";
    private static final String IP_URL_REQ_TIME = "ip_url_times_";
    private static final long LIMIT_TIMES = 5;
    private static final int IP_LOCK_TIME = 60;

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest,
                             HttpServletResponse httpServletResponse,
                             Object o) throws Exception {
        log.info("request uri={}, ip={}", httpServletRequest.getRequestURI(),
                 IpAdrressUtil.getIpAdrress(httpServletRequest));
        if (ipIsLock(IpAdrressUtil.getIpAdrress(httpServletRequest))) {
            log.info("ip access blocked={}", IpAdrressUtil.getIpAdrress(httpServletRequest));
            ApiResult result = new ApiResult(ResultEnum.LOCK_IP);
            returnJson(httpServletResponse, JSON.toJSONString(result));
            return false;
        }
        if (!addRequestTime(IpAdrressUtil.getIpAdrress(httpServletRequest),
                            httpServletRequest.getRequestURI())) {
            ApiResult result = new ApiResult(ResultEnum.LOCK_IP);
            returnJson(httpServletResponse, JSON.toJSONString(result));
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView modelAndView) throws Exception { }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) throws Exception { }

    /** Determine whether the IP is locked */
    private Boolean ipIsLock(String ip) {
        RedisUtil redisUtil = getRedisUtil();
        if (redisUtil.hasKey(LOCK_IP_URL_KEY + ip)) {
            return true;
        }
        return false;
    }

    /** Record request count */
    private Boolean addRequestTime(String ip, String uri) {
        String key = IP_URL_REQ_TIME + ip + uri;
        RedisUtil redisUtil = getRedisUtil();
        if (redisUtil.hasKey(key)) {
            long time = redisUtil.incr(key, 1L);
            if (time >= LIMIT_TIMES) {
                redisUtil.getLock(LOCK_IP_URL_KEY + ip, ip, IP_LOCK_TIME);
                return false;
            }
        } else {
            redisUtil.getLock(key, 1L, 1);
        }
        return true;
    }

    private void returnJson(HttpServletResponse response, String json) throws Exception {
        PrintWriter writer = null;
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/json; charset=utf-8");
        try {
            writer = response.getWriter();
            writer.print(json);
        } catch (IOException e) {
            log.error("LoginInterceptor response error -> {}", e.getMessage(), e);
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }
}

The Redis usage relies on a distributed lock to ensure thread safety. The example locks an IP for one hour after five requests to the same endpoint within one second; adjust the thresholds as needed.

Redis Distributed‑Lock Core Methods

public boolean getLock(String lockKey, Object value, int expireTime) {
    try {
        log.info("Adding distributed lock key={}, expireTime={}", lockKey, expireTime);
        String script = "if redis.call('setNx',KEYS[1],ARGV[1]) then " +
                        "if redis.call('get',KEYS[1])==ARGV[1] then " +
                        "return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end end";
        RedisScript<String> redisScript = new DefaultRedisScript<>(script, String.class);
        Object result = redisTemplate.execute(redisScript,
                                            Collections.singletonList(lockKey),
                                            value, expireTime);
        if (SUCCESS.equals(result)) {
            return true;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}

/** Release lock */
public boolean releaseLock(String lockKey, String value) {
    String script = "if redis.call('get', KEYS[1]) == ARGV[1] " +
                    "then return redis.call('del', KEYS[1]) else return 0 end";
    RedisScript<String> redisScript = new DefaultRedisScript<>(script, String.class);
    Object result = redisTemplate.execute(redisScript,
                                         Collections.singletonList(lockKey), value);
    if (SUCCESS.equals(result)) {
        return true;
    }
    return false;
}

Finally, register the interceptor in a WebMvcConfigurer:

@Configuration
@Slf4j
public class MyWebAppConfig extends WebMvcConfigurerAdapter {

    @Bean
    IpUrlLimitInterceptor getIpUrlLimitInterceptor() {
        return new IpUrlLimitInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(getIpUrlLimitInterceptor()).addPathPatterns("/**");
        super.addInterceptors(registry);
    }
}

You can write a simple loop to test the functionality.

Source: CSDN (original link: blog.csdn.net/wang_shuyu/article/details/102531940). Content is shared for learning purposes only.
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

redisspring-bootdistributed-lockInterceptorBackend Security
Java High-Performance Architecture
Written by

Java High-Performance Architecture

Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.