doum
2025-09-12 5e5a317f936e4e333809298930fb771fc0bdc9ac
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package com.doumee.core.annotation.pr;
 
import com.doumee.service.proxy.CacheProxy;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
 
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
 
/**
 * 防重复提交实现接口
 * @author Eva.Caesar Liu
 * @date 2023/03/21 14:49
 */
public abstract class PreventRepeatAdapter {
 
    // 请求Key前缀
    private static final String REQUEST_KEY_PREFIX = "eva:pr:";
 
    // 暴力请求Key前缀
    private static final String MASSIVE_KEY_PREFIX = "eva:massive:";
 
    @Autowired
    private CacheProxy<String, Object> cacheProxy;
 
    /**
     * 验证是否重复
     */
    public Boolean prevent(HttpServletRequest request, int interval) {
        String requestKey = REQUEST_KEY_PREFIX + this.sign(request);
        boolean isRepeat = cacheProxy.get(requestKey) != null;
        if (!isRepeat) {
            cacheProxy.put(requestKey, System.currentTimeMillis(), Long.valueOf(interval));
        }
        return isRepeat;
    }
 
    /**
     * 验证是否暴力涌入
     */
    public Boolean massive (HttpServletRequest request, int maxFreq, int lockTime) {
        String massiveKey = MASSIVE_KEY_PREFIX + this.sign(request);
        Object unit = cacheProxy.get(massiveKey);
        if (unit == null) {
            cacheProxy.put(massiveKey, new MassiveUnit(maxFreq, lockTime), 60);
            return Boolean.FALSE;
        }
        MassiveUnit massiveUnit = (MassiveUnit) unit;
        if (massiveUnit.getLock() == 1) {
            return Boolean.TRUE;
        }
        if (massiveUnit.getFreq() >= massiveUnit.getMaxFreq()) {
            massiveUnit.setLock((byte)1);
            cacheProxy.put(massiveKey, massiveUnit, Long.valueOf(massiveUnit.getLockTime()));
            return Boolean.TRUE;
        }
        massiveUnit.increment();
        cacheProxy.put(massiveKey, massiveUnit);
        return Boolean.FALSE;
    }
 
 
    /**
     * 参数签名
     */
    public abstract String sign (HttpServletRequest request);
 
    /**
     * 暴力验证单元
     */
    @Data
    static class MassiveUnit implements Serializable {
 
        private byte lock = 0;
 
        // 请求频率
        private int freq = 1;
 
        // 最高频率
        private int maxFreq;
 
        // 锁定时长
        private int lockTime;
 
        MassiveUnit (int maxFreq, int lockTime) {
            this.maxFreq = maxFreq;
            this.lockTime = lockTime;
        }
 
        void increment () {
            this.freq++;
        }
    }
}