接口拦截防止恶意攻击。
1.创建注解类(此处不再赘述注解创建)
@Retention(RUNTIME)
@Target(METHOD)
public @interface AccessLimit {
int seconds();
int maxCount();
boolean needLogin() default true;
}
2.接口的使用用例(controller层加上注解)
/**
* 此接口每分钟调用次数为5次并且需要登录才可访问
*
*/
@RequestMapping(value="/do_grow")
@ResponseBody
@AccessLimit(seconds=60, maxCount=5, needLogin=true)
public Result<CodeMsg> activity(Model model,ValidateUser user,String activityId) {
CodeMsg msg = activityService.scanGROWInc(user,activityId);
return Result.msg(msg);
}
3.注解处理器(拦截器)
@Service
public class AccessInterceptor extends HandlerInterceptorAdapter{
@Autowired
ValidateUserService userService;
@Autowired
FansService fansService;
@Autowired
RedisService redisService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String paramToken = request.getParameter(ValidateUserService.COOKI_NAME_TOKEN);
if(handler instanceof HandlerMethod) {
HandlerMethod hm = (HandlerMethod)handler;
ValidateUser user = getUser(request, response);
if(user != null) {
//判断用户是否在黑名单
CodeMsg msg = fansService.handle(user);
//如果人没问题
if(msg!=CodeMsg.PERSON_NO_PROBLEM){
if(msg.getCode()==CodeMsg.PERSON_ERROR.getCode() || msg.getCode() == CodeMsg.VALIDATE_CODE_BLACK.getCode()){
render(response, CodeMsg.NO_ACTIVITY);
return false;
}
render(response, msg);
return false;
}
}
UserContext.setUser(user);
//注解处理器
AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
if(accessLimit == null) {
return true;
}
int seconds = accessLimit.seconds();
int maxCount = accessLimit.maxCount();
boolean needLogin = accessLimit.needLogin();
String key = request.getRequestURI();
if(needLogin) {
if(user == null) {
render(response, CodeMsg.SESSION_ERROR.fillArgsToken(paramToken));
return false;
}
key += "_" + user.getOpenid();
}
AccessKey ak = AccessKey.withExpire(seconds);
Integer count = redisService.get(ak, key, Integer.class);
if(count == null) {
redisService.set(ak, key, 1);
}else if(count < maxCount) {
redisService.incr(ak, key);
}else {
render(response, CodeMsg.ACCESS_LIMIT_REACHED.fillArgsToken(paramToken));
return false;
}
}
return true;
}
private void render(HttpServletResponse response, CodeMsg cm)throws Exception {
response.setContentType("application/json;charset=UTF-8");
OutputStream out = response.getOutputStream();
String str = JSON.toJSONString(Result.error(cm));
out.write(str.getBytes("UTF-8"));
out.flush();
out.close();
}
private ValidateUser getUser(HttpServletRequest request, HttpServletResponse response) {
String paramToken = request.getParameter(ValidateUserService.COOKI_NAME_TOKEN);
if(StringUtils.isEmpty(paramToken)) {
return null;
}
return userService.getByToken(response, paramToken);
}