防止重放攻击,简单来说就是防止短时间内多次恶意访问
方法:
@ResponseBody
@RequestMapping(value = "/saveOrUpdate", method = RequestMethod.POST)
@RequestLimit
public Object saveOrUpdate(MallStore store, HttpServletRequest request) {
注解:@RequestLimit
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestLimit {
int time() default 60; //60s内
int count() default 50; //访问超过50次后拒绝访问
int waits() default 300; //超过后等待时间
}
AOP处理注解
@Aspect
@Component
@Order(6)
public class RequestLimitAspect {
private static final String REQ_LIMIT = "req_limit_";
/**
* 定义拦截规则:拦截com.springboot.bcode.api包下面的所有类中,有@RequestLimit Annotation注解的方法
* 。
*/
@Around("execution(* com.xxx.xxxcontroller..*.*(..)) && @annotation(com.xxx.xxx.xxx.common.security.RequestLimit)")
public Object method(ProceedingJoinPoint pjp) throws Throwable {
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod(); // 获取被拦截的方法
RequestLimit limt = method.getAnnotation(RequestLimit.class);
// No request for limt,continue processing request
if (limt == null) {
return pjp.proceed();
}
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = sra.getRequest();
int time = limt.time();
int count = 3;
int waits = limt.waits();
String ip = RequestUtil.getIpAddr(request);
String url = request.getRequestURI();
String limitValue = "";
StoreUpmsPrincipal principal1 = (StoreUpmsPrincipal) SecurityUtils.getSubject().getPrincipal();
if (principal1 == null) {
limitValue = principal1.getUserId().toString();
}else {
limitValue = ip;
}
// judge codition
String key = requestLimitKey(url, limitValue);
int nowCount = RedisUtil.get(key) == null ? 0 : Integer.valueOf(RedisUtil
.get(key));
if (nowCount == 0) {
nowCount++;
RedisUtil.set(key, String.valueOf(nowCount), time);
return pjp.proceed();
} else {
nowCount++;
RedisUtil.set(key, String.valueOf(nowCount), time);
if (nowCount >= count) {
System.out.println("用户IP[" + ip + "]访问地址[" + url + "]访问次数["
+ nowCount + "]超过了限定的次数[" + count + "]限定时间[" + waits
+ "秒]");
RedisUtil.expire(key, waits);
return returnLimit(request);
}
}
return pjp.proceed();
}
/**
* requestLimitKey: url_ip
*
* @param url
* @param ip
* @return
*/
private static String requestLimitKey(String url, String ip) {
StringBuilder sb = new StringBuilder();
sb.append(REQ_LIMIT);
sb.append(url);
sb.append("_");
sb.append(ip);
return sb.toString();
}
/**
* 返回拒绝信息
*
* @param request
* @return
* @throws IOException
*/
private String returnLimit(HttpServletRequest request) throws IOException {
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getResponse();
PrintWriter out = response.getWriter();
response.setCharacterEncoding("utf-8");
response.setContentType("application/json; charset=utf-8");
out.println("{\"code\": 50004,\"msg\":\"Service reject request!\"}");
out.flush();
out.close();
return null;
}
}