Spring boot接口防刷


Springboot接口防刷

自定义注解

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
 
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AccessLimit {
 
    int seconds();
    int maxCount();
    boolean needLogin() default true;
}

拦截器

用户的 ID和请求的路径作为key,首先从redis中根据该key去取得用户的访问次数,如果为null,则根据该key重新设置key,value,value的值是1,能取到key对应的value,则判断vlaue是否小于5,是则处理请求,否则返回error。

import com.alibaba.fastjson.JSON;
import com.example.demo.action.AccessLimit;
import com.example.demo.redis.RedisService;
import com.example.demo.result.CodeMsg;
import com.example.demo.result.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
 
@Component
public class AntiBrushInterceptor extends HandlerInterceptorAdapter {
 
    @Autowired
    private RedisService redisService;
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
 
        if(handler instanceof HandlerMethod){
 
            HandlerMethod hm = (HandlerMethod) handler;
 
            AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
            if(accessLimit == null){
                return true;
            }
            int seconds = accessLimit.seconds();
            int maxCount = accessLimit.maxCount();
            boolean login = accessLimit.needLogin();
            String key = request.getRequestURI();
            if(login){
                //业务逻辑
            }
 
            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); 
                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();
    }
}

拦截器注册和注解使用

import com.example.demo.ExceptionHander.AntiBrushInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
 
    @Autowired
    private AntiBrushInterceptor interceptor;
 
 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(interceptor);
    }
}
@PostMapping("getNewsModule")
@AccessLimit(seconds=5, maxCount=10, needLogin=true)
public Result> getNewsModule(@ApiIgnore @RequestParam Map params){
        PageData page = newsModuleService.page(params);
        return new Result>().ok(page.getList());
    }

文章作者: dinggc
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 dinggc !
评论
 上一篇
python学习笔记(一) python学习笔记(一)
python学习笔记(一) python函数 print输出函数 id(var) 获取对象的唯一id type(var) 获取对象的类型 var 存储的值 open函数 var3 = open(var1 var2) var1参数值代表输出文
2021-03-27
下一篇 
使用docker创建项目镜像 使用docker创建项目镜像
使用docker创建项目镜像 本文创建的镜像为hexo静态博客的镜像,防止自己的服务器到期之后进行迁移的麻烦。 确定创建镜像所需的环境 node.js git nginx 编写自己的镜像的Dockerfile文件 docker指令详解
2021-02-05
  目录