Java利用redis限制用戶頻繁點擊操作
一、場景
為了系統(tǒng)安全,有時候需要做一些限制用戶的操作。比如用戶惡意刷接口,或者系統(tǒng)卡頓時候頻繁點擊,輕則造成系統(tǒng)崩潰,重則可能造成數(shù)據(jù)丟失。不得不引起重視。
解決方案:使用redis和攔截器來記錄并控制用戶行為
二、攔截器
ResponseParams為本地的一個異常處理對象,自己可以使用自己的對象
package simple.cloud.config.myInterceptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import net.sf.json.JSONArray;
import simple.cloud.components.common.params.ResponseParams;
import simple.cloud.components.common.utils.MyUtils;
@Component
@CrossOrigin("*")
public class MyInterceptor implements HandlerInterceptor {
@Resource
private RedisTemplate<String, Object> redisTemplate;
/**
* 1、過濾封禁IP
* 2、過濾惡意IP
*/
@Override
@CrossOrigin("*")
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (handler.getClass().isAssignableFrom(HandlerMethod.class)) { // 判斷此class對象所表示的類或接口與指定的class參數(shù)所表示的類或接口是否相同
//1、校驗IP合法
String ip = MyUtils.getIpAddress(request);
String limitKey = request.getServletPath() + MyUtils.getIpAddress(request);
Object blackIp = redisTemplate.opsForValue().get(ip);
if (MyUtils.isNotNull(blackIp)) {
respouseOut(response, ResponseParams.error("禁止使用!"));
return false;
}
//2、校驗重復(fù)點擊
// HandlerMethod封裝方法定義相關(guān)的信息,如類、方法、參數(shù)等
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
// 獲取方法中是否包含注解
MyLimit methodAnnotation = method.getAnnotation(MyLimit .class);
// 獲取類中是否包含注解
MyLimit classAnnotation = method.getDeclaringClass().getAnnotation(MyLimit .class);
// 如果方法上有注解 就優(yōu)先選擇方法上的參數(shù)
MyLimit myLimit = methodAnnotation != null ? methodAnnotation : classAnnotation;
if (requestLimit != null) {
if (checkLimit(limitKey, myLimit )) {
respouseOut(response, ResponseParams.error("您點擊的太頻繁啦!"));
//將被封禁的IP加入緩存,下次訪問時不必校驗其點擊情況
redisTemplate.opsForValue().set(ip , 1, 30, TimeUnit.SECONDS);
return false;
}
}
}
return true;
}
/**
* 回寫給客戶端
*/
private void respouseOut(HttpServletResponse response, ResponseParams resp) throws IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charaset=utf-8");
PrintWriter out = null;
String json = com.alibaba.fastjson.JSONObject.toJSON(resp).toString();
out = response.getWriter();
out.append(json);
}
/**
* 判斷請求是否受限
*/
private boolean checkLimit(String limitKey, RequestLimit requestLimit) {
//使用IP+請求地址作為key
//從緩存中獲取,當(dāng)前這個請求訪問了幾次
Integer redisCount = (Integer) redisTemplate.opsForValue().get(limitKey);
if (redisCount == null) {
//初始次數(shù)
redisTemplate.opsForValue().set(limitKey, 1, requestLimit.second(), TimeUnit.SECONDS);
} else {
//若在指定時間內(nèi)超過了訪問次數(shù)限制,則返回true
if (redisCount.intValue() >= requestLimit.maxCount()) {
//將其設(shè)置超過限制次數(shù),并延遲30秒,30秒之后可以重新訪問
redisTemplate.opsForValue().set(limitKey, requestLimit.maxCount()+1, 30, TimeUnit.SECONDS);
return true;
}
//次數(shù)自增
redisTemplate.opsForValue().increment(limitKey, 1);
}
return false;
}
}MyLimit為一個注解,可以添加在指定controller上,來精確限制用戶行為
@Documented
@Inherited
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLimit {
int second() default 1;
int maxCount() default 15;
}三、添加攔截器
值得注意的是需要添加crosFiter方法,來解決攔截器跨越問題
@Resource
private MyInterceptor myInterceptor;
/**
* 讓cors高于攔截器的權(quán)限
* 解決攔截器CROS問題
* @return
*/
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.setAllowCredentials(true);
config.addAllowedMethod("*");
config.addAllowedHeader("*");
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
return new CorsFilter(configSource);
}
/**
* 添加我的默認(rèn)的攔截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor).addPathPatterns("/**");
}到此這篇關(guān)于Java利用redis限制用戶頻繁點擊操作的文章就介紹到這了,更多相關(guān)java redis限制頻繁點擊內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringMVC DispatcherServlet組件實現(xiàn)解析
這篇文章主要介紹了SpringMVC DispatcherServlet組件實現(xiàn)解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03
Java?MethodHandles介紹與反射對比區(qū)別詳解
這篇文章主要為大家介紹了Java?MethodHandles介紹與反射對比區(qū)別詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
Thymeleaf渲染網(wǎng)頁時中文亂碼的問題及解決
這篇文章主要介紹了Thymeleaf渲染網(wǎng)頁時中文亂碼的問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-02-02
springboot中websocket簡單實現(xiàn)
本文主要介紹了springboot中websocket簡單實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01

