博客
关于我
SpringBoot 接口防刷(注解实现)
阅读量:583 次
发布时间:2019-03-11

本文共 5463 字,大约阅读时间需要 18 分钟。

使用注解实现接口防刷功能

注解类定义

我们定义了一个注解类 AccessLimit,用于限制接口的调用次数和防止恶意刷接口。该注解的主要字段包括:

  • seconds():接口有效时间,单位为秒。
  • maxCount():最大允许调用次数。
  • needLogin():是否需要登录验证(默认为 true)。
import java.lang.annotation.Retention;import java.lang.annotation.Target;import static java.lang.annotation.ElementType.METHOD;import static java.lang.annotation.RetentionPolicy.RUNTIME;@Retention(RUNTIME)@Target(METHOD)public @interface AccessLimit {    int seconds();    int maxCount();    boolean needLogin() default true;}

拦截器实现

接下来,我们创建了一个 FangshuaInterceptor 拦截器,用于检查请求是否超过访问限制。拦截器通过以下步骤实现防刷功能:

  • 检查 HandlerMethod 是否存在 AccessLimit 注解。
  • 如果没有注解,直接通过。
  • 如果有注解,获取注解配置:
    • seconds():接口有效时间。
    • maxCount():最大允许调用次数。
    • needLogin():是否需要登录验证。
  • 如果需要登录,获取用户信息并构建唯一标识符。
  • 从 Redis 缓存中获取用户的访问次数。
  • 判断访问次数是否超过限制:
    • 如果是第一次访问,记录一次。
    • 如果在限制内,允许访问并记录最新次数。
    • 如果超过限制,返回错误信息。
  • import com.alibaba.fastjson.JSON;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;@Componentpublic class FangshuaInterceptor 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) {                // 假设用户是动态获取的 userId                key += "1";            }            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();    }}

    拦截器注册

    在 Spring Boot 应用中,我们通过 WebConfig 注册拦截器:

    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;@Componentpublic class FangshuaInterceptor 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) {                // 假设用户是动态获取的 userId                key += "1";            }            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();    }}

    Controller 注解应用

    在实际应用中,我们可以在需要防刷的接口上添加 AccessLimit 注解,并指定相关参数:

    import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;@Controllerpublic class FangshuaController {    @AccessLimit(seconds=5, maxCount=5, needLogin=true)    @RequestMapping("/demo")    @ResponseBody    public Result fangshua() {        return Result.success("请求成功");    }}

    总结

    通过以上方案,我们可以轻松地在 Spring Boot 应用中实现接口防刷功能。这种方式的优点包括:

  • 灵活性:可以对不同接口设置不同的访问限制。
  • 可扩展性:支持多种防刷策略,如时间限制和次数限制。
  • 非破坏性:不需要修改接口签名,适用于已有接口。
  • 易于部署:通过 Redis 缓存实现高性能和高可用性。
  • 这种解决方案在实际应用中表现良好,能够有效防止接口被恶意刷击,同时保持服务的正常运行。

    转载地址:http://sbytz.baihongyu.com/

    你可能感兴趣的文章
    PowerDesigner使用教程:时间字段设置
    查看>>
    PowerDesigner使用教程:给字段添加唯一约束
    查看>>
    QGIS中怎样设置图层样式并导出地图样式
    查看>>
    PowerDesigner使用笔记
    查看>>
    QGIS中怎样实现数据坐标系转换
    查看>>
    PowerDesigner学习--基本步骤
    查看>>
    PowerDesigner导出Report通用报表
    查看>>
    PowerDesigner教程系列(二)概念数据模型
    查看>>
    Powerdesigner显示表的comment和列的comment的方法
    查看>>
    PowerDesigner最基础的使用方法入门学习
    查看>>
    PowerDesigner版本控制器设置权限
    查看>>
    PowerDesigner生成数据模型并导出报告
    查看>>
    QGIS中导入dwg文件并使用GetWKT插件获取绘制元素WKT字符串以及QuickWKT插件实现WKT显示在图层
    查看>>
    PowerDesigner逆向工程从SqlServer数据库生成PDM(图文教程)
    查看>>
    PowerEdge T630服务器安装机器学习环境(Ubuntu18.04、Nvidia 1080Ti驱动、CUDA及CUDNN安装)
    查看>>
    PowerPC-object与elf中的符号引用
    查看>>
    QFileSystemModel
    查看>>
    Powershell DSC 5.0 - 参数,证书加密账号,以及安装顺序
    查看>>
    PowerShell 批量签入SharePoint Document Library中的文件
    查看>>
    Powershell 自定义对象小技巧
    查看>>