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;

/**
 * 限制接口訪問
 */
@Retention(RUNTIME)
@Target(METHOD)
public @interface AccessLimit {
    /**
     * 秒
     * @return
     */
    int seconds();

    /**
     * 最大請求數量
     * @return
     */
    int maxCount();

    /**
     * 是否需要登錄
     * @return
     */
    boolean needLogin() default true;

}

 

攔截器邏輯:

import com.alibaba.fastjson.JSON;
import com.emi2c.mybatis.config.annotation.AccessLimit;
import com.emi2c.mybatis.util.RedisUtil;
import com.emi2c.mybatis.util.ResultUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
import java.util.Map;
import java.util.Objects;

@Component
public class AccessInterceptor extends HandlerInterceptorAdapter {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private RedisUtil redisUtil;

    @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 seconds = accessLimit.seconds();
            // 訪問次數
            int maxCount = accessLimit.maxCount();
            // 是否需要登陸
            boolean needLogin = accessLimit.needLogin();
            String key = request.getRequestURI();
            logger.info("訪問地址: {}", key);
            // 是否需要登陸
            if(needLogin) {
                String username = request.getHeader("username");
                key = key + "-" + username;
            }

            // 已訪問次數
            Object o = redisUtil.get(key);
            if(Objects.isNull(o)) {
                // 第一次訪問
                redisUtil.incr(key, 1);
                redisUtil.expire(key, seconds);
            } else {
                // 獲取單位時間內已訪問次數
                Integer count = Integer.valueOf(redisUtil.get(key).toString());
                if(maxCount > count) {
                    // 沒超出訪問限制
                    redisUtil.incr(key, 1);
                } else {
                    // 超出訪問限制
                    logger.info("訪問次數超出限制");
                    Map<String, Object> failure = ResultUtil.getFailure(200, "訪問次數超出限制");
                    render(response, failure);
                    return false;
                }
            }
        }
        return true;
    }


    /**
     * 封裝消息
     * @param response
     * @param message
     * @throws Exception
     */
    private void render(HttpServletResponse response, Map<String, Object> message)throws Exception {
        response.setContentType("application/json;charset=UTF-8");
        OutputStream out = response.getOutputStream();
        String str  = JSON.toJSONString(message);
        out.write(str.getBytes("UTF-8"));
        out.flush();
        out.close();
    }

}

 

注冊攔截器:

import com.emi2c.mybatis.config.interceptor.AccessInterceptor;
import com.emi2c.mybatis.config.interceptor.OperatingInterceptor;
import org.springframework.context.annotation.Bean;
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 WebAppConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注冊自己的攔截器並設置攔截的請求路徑
        registry.addInterceptor(getOperatingInterceptor()).addPathPatterns("/**");
        registry.addInterceptor(getAccessInterceptor()).addPathPatterns("/**");
        super.addInterceptors(registry);
    }

    /**
     * 解決攔截器內對象注入失敗問題
     *
     * @return
     */
    @Bean
    public OperatingInterceptor getOperatingInterceptor() {
        return new OperatingInterceptor();
    }

    @Bean
    public AccessInterceptor getAccessInterceptor() {
        return new AccessInterceptor();
    }

}

 

注解使用:

import com.emi2c.mybatis.config.annotation.AccessLimit;
import com.emi2c.mybatis.util.ResultUtil;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

/**
 * 防刷接口
 */
@RestController
public class UnFlushController {
    
// 5秒內最多允許5次訪問 @AccessLimit(maxCount
= 5, seconds = 5, needLogin = true) @RequestMapping(value = "flush", method = RequestMethod.GET) public Map<String, Object> unFlush() { return ResultUtil.getSuccess(); } }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM