Spring Boot(五十五):基于redis防止接口恶意刷新和暴力请求 您所在的位置:网站首页 spring应用下载 Spring Boot(五十五):基于redis防止接口恶意刷新和暴力请求

Spring Boot(五十五):基于redis防止接口恶意刷新和暴力请求

2023-01-23 07:21| 来源: 网络整理| 查看: 265

下面的教程,通过intercept和redis针对url+ip在一定时间内访问的次数来将ip禁用,可以根据自己的需求进行相应的修改,来达到自己的目的

下面只讲解大致步骤,不详细讲解,需要完整代码的可以自行下载。

https://download.csdn.net/download/u013938578/87389620

新建SpringBoot项目:

 拦截器类如下:

        对访问ip地址进行识别和判断。

package com.example.demo.Interceptor; import com.alibaba.fastjson.JSON; import com.example.demo.Utils.IpAdrressUtil; import com.example.demo.Utils.RedisUtil; import com.example.demo.entity.Result; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; @Slf4j @Component @RequiredArgsConstructor public class IpUrlLimitInterceptor implements HandlerInterceptor { private final RedisUtil redisUtil; 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 String IP_LOCK_TIME = "60"; @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { log.info("request请求地址uri={},ip={}", httpServletRequest.getRequestURI(), IpAdrressUtil.getIpAddr(httpServletRequest)); if (ipIsLock(IpAdrressUtil.getIpAddr(httpServletRequest))) { log.info("ip访问被禁止={}", IpAdrressUtil.getIpAddr(httpServletRequest)); returnJson(httpServletResponse, JSON.toJSONString(Result.success("ip访问被禁止"))); return false; } if (!addRequestTime(IpAdrressUtil.getIpAddr(httpServletRequest), httpServletRequest.getRequestURI())) { returnJson(httpServletResponse, JSON.toJSONString(Result.success("ip访问被禁止"))); return false; } return true; } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } /** * 判断ip是否被禁用 * * @param ip * @return */ private Boolean ipIsLock(String ip) { if (redisUtil.hasKey(LOCK_IP_URL_KEY + ip)) { return true; } return false; } /** * 记录请求次数 * * @param ip * @param uri * @return */ private Boolean addRequestTime(String ip, String uri) { String key = IP_URL_REQ_TIME + ip + uri; if (redisUtil.hasKey(key)) { // 如果key存在,次数+1 long time = redisUtil.incr(key, (long) 1); log.info("time:{}", time); if (time >= LIMIT_TIMES) { // 如果超过限制次数,则设置ip被禁用 60秒 redisUtil.getLock(LOCK_IP_URL_KEY + ip, ip, IP_LOCK_TIME); return false; } } else { // ip+uri请求次数为1,1秒后过期 redisUtil.getLock(key, "1", "1"); log.info("记录请求次数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(); } } } }

拦截器配置文件:

package com.example.demo.Config; import com.example.demo.Interceptor.IpUrlLimitInterceptor; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration @Slf4j @RequiredArgsConstructor public class MyWebAppConfig implements WebMvcConfigurer { private final IpUrlLimitInterceptor ipUrlLimitInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(ipUrlLimitInterceptor).addPathPatterns("/**"); } }

代码中redis的使用的是分布式锁的形式,这样可以最大程度保证线程安全和功能的实现效果。代码中设置的是1S内同一个接口通过同一个ip访问5次,就将该ip禁用1个小时,根据自己项目需求可以自己适当修改,实现自己想要的功能;

redis分布式锁代码:

package com.example.demo.Utils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.data.redis.core.script.RedisScript; import org.springframework.stereotype.Component; import java.util.Collections; @Component @Slf4j @RequiredArgsConstructor public class RedisUtil { private static final Long SUCCESS = 1L; private final RedisTemplate redisTemplate; /** * 获取锁 * * @param lockKey * @param value * @param expireTime:单位-秒 * @return */ public boolean getLock(String lockKey, Object value, String expireTime) { boolean ret = false; try { 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 redisScript = new DefaultRedisScript(script, Long.class); Long result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey), value, expireTime); log.info("result:{}", result); if (SUCCESS.equals(result)) { return true; } } catch (Exception e) { log.error("getLock error:{}", e.getMessage(), e); } return ret; } /** * 释放锁 * * @param lockKey * @param value * @return */ 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 redisScript = new DefaultRedisScript(script, String.class); Object result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey), value); if (SUCCESS.equals(result)) { return true; } return false; } /** * 设置一个自增的数据 * * @param key * @param num */ public Long incr(String key, Long num) { return redisTemplate.opsForValue().increment(key, num); } public Boolean hasKey(String key) { return redisTemplate.hasKey(key); } }

获取Ip地址功能类如下:

package com.example.demo.Utils; import javax.servlet.http.HttpServletRequest; import java.net.InetAddress; import java.net.UnknownHostException; public class IpAdrressUtil { /** * 获取IP地址 */ public static String getIpAddr(HttpServletRequest request){ String ipAddress = request.getHeader("x-forwarded-for"); if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("Proxy-Client-IP"); } if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("WL-Proxy-Client-IP"); } if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddr(); if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){ //根据网卡取本机配置的IP InetAddress inet=null; try { inet = InetAddress.getLocalHost(); } catch (UnknownHostException e) { } if (inet.getHostAddress() != null) { ipAddress= inet.getHostAddress(); } } } //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15 if(ipAddress.indexOf(",")>0){ ipAddress = ipAddress.substring(0,ipAddress.indexOf(",")); } } return ipAddress; } }

第一次访问接口结果如下:

当快速多次访问接口以后,接口返回结果如下:

查看redis发现已经对ip地址加上了锁:



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有