使用redis计数来控制单位时间内对某接口的访问量,防止刷验证码接口之类的
2017-07-06 15:01
453 查看
使用自定义注解的方式,在需要被限制访问频率的方法上加注解即可控制。
看实现方式,基于springboot,aop,redis。
新建Springboot工程,引入redis,aop。
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import java.lang.annotation.*;
/**
* Created by wuwf on 17/7/6.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
//最高优先级
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface RequestLimit {
/**
* 允许访问的次数
*/
int count() default 5;
/**
* 时间段,多少时间段内运行访问count次
*/
long time() default 60000;
}
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* Created by admin on 17/7/6.
*/
public class HttpRequestUtil {
/**
* 获取当前网络ip
*
* @param request
* @return
*/
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) {
e.printStackTrace();
}
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;
}
}
看实现方式,基于springboot,aop,redis。
新建Springboot工程,引入redis,aop。
创建注解
package com.tianyalei.annotation;import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import java.lang.annotation.*;
/**
* Created by wuwf on 17/7/6.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
//最高优先级
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface RequestLimit {
/**
* 允许访问的次数
*/
int count() default 5;
/**
* 时间段,多少时间段内运行访问count次
*/
long time() default 60000;
}
Aspect切面处理逻辑
package com.tianyalei.aspect; import com.tianyalei.annotation.RequestLimit; import com.tianyalei.util.HttpRequestUtil; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.util.concurrent.TimeUnit; /** * Created by wuwf on 17/7/6. */ @Component @Aspect public class RequestLimitAspect { private final Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private RedisTemplate<String, String> redisTemplate; @Before("execution(public * com.tianyalei.controller.*.*(..)) && @annotation(limit)") public void requestLimit(JoinPoint joinpoint, RequestLimit limit) { // 接收到请求,记录请求内容 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); String ip = HttpRequestUtil.getIpAddr(request); String url = request.getRequestURL().toString(); String key = "req_limit_".concat(url).concat(ip); //加1后看看值 long count = redisTemplate.opsForValue().increment(key, 1); //刚创建 if (count == 1) { //设置1分钟过期 redisTemplate.expire(key, limit.time(), TimeUnit.MILLISECONDS); } if (count > limit.count()) { logger.info("用户IP[" + ip + "]访问地址[" + url + "]超过了限定的次数[" + limit.count() + "]"); throw new RuntimeException("超出访问次数限制"); } } }
获取IP的工具类
package com.tianyalei.util;import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* Created by admin on 17/7/6.
*/
public class HttpRequestUtil {
/**
* 获取当前网络ip
*
* @param request
* @return
*/
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) {
e.printStackTrace();
}
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;
}
}
通过Controller验证
@RestController public class IndexController { @RequestLimit(count = 4) @GetMapping("/index") public Object index() { return 1; } }启动工程,多次访问index看看效果即可。
相关文章推荐
- springboot和redis控制单位时间内同个ip访问同个接口的次数
- jmeter 使用时间戳去redis获取验证码实现有验证码登录接口测试
- 使用Redis防止重复提交.并且控制 访问频率
- 使用redis进行用户接口访问时间次数限制
- [转] 使用反射机制控制Toast的显示时间
- 防止用户直接访问url的权限控制(使用过滤器)
- 在javascript中使用时间戳可以防止IE缓存
- (遍历)一些基本的求和,求积,求阶乘,计数问题(流程控制语句的使用)
- 使用GPIO控制SPI接口的AD芯片 (转)
- 关于redis使用set时设置超时时间的问题
- [转]建议Font-Size使用em单位控制大小
- 使用Apache对网站的并发请求进行控制,防止网站瘫痪
- 第十三章(复制控制) 智能指针(使用计数)、定义值型类
- HQL或SQL使用?带来的好处:减少SQL解析时间、降低内存开销、防止SQL注入
- 使用javascript实现有效时间的控制,并显示将要过期的时间
- 使用WdatePicker时间插件简单的控制页面上两个时间选择的前后范围
- 使用GPIO控制SPI接口的AD芯片//来源不详
- Effective C# 使用时间定义外发接口
- 在javascript中使用时间戳可以防止IE缓存
- 天翼开放平台免费短信验证码接口使用实例