博客
关于我
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/

    你可能感兴趣的文章
    NFinal学习笔记 02—NFinalBuild
    查看>>
    NFS共享文件系统搭建
    查看>>
    nfs复习
    查看>>
    NFS网络文件系统
    查看>>
    nft文件传输_利用remoting实现文件传输-.NET教程,远程及网络应用
    查看>>
    ng 指令的自定义、使用
    查看>>
    Nginx
    查看>>
    nginx + etcd 动态负载均衡实践(二)—— 组件安装
    查看>>
    nginx + etcd 动态负载均衡实践(四)—— 基于confd实现
    查看>>
    Nginx + Spring Boot 实现负载均衡
    查看>>
    Nginx + uWSGI + Flask + Vhost
    查看>>
    Nginx - Header详解
    查看>>
    Nginx Location配置总结
    查看>>
    Nginx Lua install
    查看>>
    Nginx upstream性能优化
    查看>>
    Nginx 中解决跨域问题
    查看>>
    Nginx 动静分离与负载均衡的实现
    查看>>
    Nginx 反向代理 MinIO 及 ruoyi-vue-pro 配置 MinIO 详解
    查看>>
    nginx 反向代理 转发请求时,有时好有时没反应,产生原因及解决
    查看>>
    Nginx 反向代理解决跨域问题
    查看>>