基于注解的接口防刷功能

说明:本项目是基于springBoot,注意是基于注解的形式,利用redis的incr命令实现,仅供参考用,springBoot项目,以及redis需要自己搭建,这里不做详细描述,主要是提供思路,如果有需要交流,请大家在下面留言,话不多说,直接上代码。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 防刷注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AccessLimit {
    int seconds();
    int maxCount();
    boolean needLogin() default true;
}

import com.alibaba.fastjson.JSON;
import com.vipkid.parent.common.Constants;
import com.vipkid.parent.common.RedisCluster;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;

/**
 * @program:
 * @description:拦截器实现
 * @author:tsh
 * @create:2019-04-14 13:53
 */
@Component
public class AntiBrushInterceptor extends HandlerInterceptorAdapter {

    private Logger logger = (Logger) LoggerFactory.getLogger(AntiBrushInterceptor.class);

    @Autowired
    private RedisCluster redisCluster;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception{
        //判断请求是否方法的请求
        if(handler instanceof HandlerMethod){
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            //获取方法中的注解,看看是否有注解
            AccessLimit accessLimit = handlerMethod.getMethodAnnotation(AccessLimit.class);
            if(accessLimit == null){
                return true;
            }
            int second = accessLimit.seconds();
            int maxCount = accessLimit.maxCount();
            boolean login = accessLimit.needLogin();
            String key = request.getRequestURI();
            //如果需要登录
            if(login){
                String token = request.getHeader(Constants.Auth.HTTP_HEADER_TOKEN);
                //获取登录的session进行判断
//                key += ""+"1";  //这里假设用户是1,项目中是动态获取的userId
                if(token != null){
                    key = token + "|" +key;
                }
            }
            //从redis中获取用户的登录次数
            String value = redisCluster.get(key);
            if(value != null){
                Integer count = Integer.valueOf(value);
                if(count < maxCount){
                    redisCluster.incr(key,second);
                }else {
                    //超出访问次数
                    String mess = "当前总数:" + count + ";最大总数:" + maxCount;
                    logger.info("超出限制范围了:{}",mess);
                    render(response); //这里的CodeMsg是一个返回参数
                    return false;
                }
            }else {
                redisCluster.set(key,"1");
            }
        }
        return true;
    }

    private void render(HttpServletResponse httpServletResponse)throws Exception{
        httpServletResponse.setContentType("application/json;charset=UTF-8");
        OutputStream outputStream = httpServletResponse.getOutputStream();
        String str = JSON.toJSONString(CodeMsg.ACCESS_LIMIT_REACHED);
        outputStream.write(str.getBytes("UTF-8"));
        outputStream.flush();
        outputStream.close();
    }


}
/**
 * @program:
 * @description:错误码描述
 * @author:tsh
 * @create:2019-04-15 10:32
 */
public class CodeMsg {
    public static String ACCESS_LIMIT_REACHED = "ACCESS_LIMIT_REACHED";
}
/**
 * @program:
 * @description:
 * @author:tsh
 * @create:2019-04-14 14:15
 */
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Autowired
    private AntiBrushInterceptor antiBrushInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry){
            registry.addInterceptor(antiBrushInterceptor);
    }

}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 防刷注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AccessLimit {
    int seconds();
    int maxCount();
    boolean needLogin() default true;
}
import com.vipkid.parent.dto.RetDTO;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @program:
 * @description:测试类
 * @author:tsh
 * @create:2019-04-15 10:50
 */

@RestController
@RequestMapping(value = "/api/autiBrush")
public class AntiBrushController {
    @AccessLimit(seconds = 5,maxCount = 5,needLogin = true)
    @RequestMapping(value = "/test")
    @ResponseBody
    public RetDTO autiBrushTest(){
        RetDTO result = new RetDTO(200, "基于token的防刷接口测试");
        return result;
    }
}

 

你可能感兴趣的:(基于注解的接口防刷功能)