@@ -103,6 +103,22 @@ public class AnonymousViewCheckMidware {
103103 // String类型的白名单
104104 public static final Set <String > whiteList = new HashSet <>();
105105
106+ /**
107+ * IP 首次访问时间缓存(用于 2 小时内首次访问需要验证码)
108+ */
109+ public static final Cache <String , Long > ipFirstVisitTimeCache = Caffeine .newBuilder ()
110+ .expireAfterWrite (2 , java .util .concurrent .TimeUnit .HOURS )
111+ .maximumSize (100000 )
112+ .build ();
113+
114+ /**
115+ * IP 最近一次通过验证码的时间(通过后重置计数逻辑时使用)
116+ */
117+ public static final Cache <String , Long > ipLastCaptchaPassTimeCache = Caffeine .newBuilder ()
118+ .expireAfterWrite (2 , java .util .concurrent .TimeUnit .HOURS )
119+ .maximumSize (100000 )
120+ .build ();
121+
106122 private static Cookie getCookie (final Request request , final String name ) {
107123 final Set <Cookie > cookies = request .getCookies ();
108124 if (cookies .isEmpty ()) {
@@ -144,22 +160,47 @@ public void handle(final RequestContext context) {
144160 } else {
145161 final String ua = Headers .getHeader (request , Common .USER_AGENT , "" );
146162 if (!isSearchEngineBot (ua )) {
147- // 计数逻辑
163+ // 初始化首次访问时间(用于 2 小时内首次访问逻辑)
164+ Long firstVisitTime = ipFirstVisitTimeCache .getIfPresent (ip );
165+ long now = System .currentTimeMillis ();
166+ if (firstVisitTime == null ) {
167+ firstVisitTime = now ;
168+ ipFirstVisitTimeCache .put (ip , firstVisitTime );
169+ }
170+
171+ // 计数逻辑(包含两种策略:2 小时内首次访问一次验证码,其后每 3 次一次)
148172 Integer count = ipVisitCountCache .getIfPresent (ip );
149173 if (count == null ) count = 0 ;
150174 count ++;
151175 ipVisitCountCache .put (ip , count );
152176 System .out .println (ip + " 访问计数:" + count + " " + context .requestURI ());
153- if (count >= 300 ) {
177+
178+ if (count >= 20 ) {
154179 String result = Execs .exec (new String []{"sh" , "-c" , "ipset add fishpi " + ip }, 1000 * 3 );
155180 System .out .println (ip + " 已封禁" );
156181 }
157- if (count >= 5 ) {
158- // 进入黑名单
182+
183+ // 判断是否需要进入验证码流程
184+ boolean needCaptcha = false ;
185+
186+ // 2 小时内首次访问:第一次就需要验证码
187+ Long lastPassTime = ipLastCaptchaPassTimeCache .getIfPresent (ip );
188+ if (lastPassTime == null && (now - firstVisitTime ) <= 2L * 60L * 60L * 1000L ) {
189+ if (count == 1 ) {
190+ needCaptcha = true ;
191+ }
192+ }
193+
194+ // 之后每访问 3 次需要一次验证码
195+ if (!needCaptcha && count % 3 == 0 ) {
196+ needCaptcha = true ;
197+ }
198+
199+ if (needCaptcha ) {
200+ // 进入黑名单并跳转验证码页面
159201 ipBlacklistCache .put (ip , true );
160- // 跳转到验证码页面
161202 context .sendRedirect ("/test" );
162- System .out .println (ip + " 进入黑名单" );
203+ System .out .println (ip + " 触发验证码, 进入黑名单" );
163204 return ;
164205 }
165206 }
0 commit comments