redis防止短信惡意調(diào)用的實(shí)現(xiàn)
1.場景
登錄或注冊接口中,使用短信驗(yàn)證碼場景時(shí),遇到惡意調(diào)用短信接口,一毫秒多次調(diào)用,導(dǎo)致短信資源大幅度消耗。
2.排查
經(jīng)排查發(fā)現(xiàn),短信發(fā)送接口無限制,僅通過redis保留驗(yàn)證碼發(fā)送信息。一個(gè)時(shí)間戳產(chǎn)生數(shù)次甚至十幾次調(diào)用,多個(gè)線程同時(shí)訪問redis后,取值相同,均通過驗(yàn)證前往調(diào)用短信接口。
3.解決方案
使用redis分布式鎖,解決該問題。
相關(guān)代碼如下:
3.1 redis鎖實(shí)現(xiàn)
public class RedisLock {
@Autowired
private RedisTemplate<String, String> redisTemplate;
private static final Long NX = 1L; // 超時(shí)時(shí)間
public boolean tryLock(String key, String value) {
// 超時(shí)時(shí)間單位,這里發(fā)現(xiàn),較新版本的RedisTemplate中,setIfAbsent方法時(shí)間單位為TimeUnit,并非大多帖子中表述的Long類型
TimeUnit timeUnit = TimeUnit.MINUTES;
// 這里設(shè)置redis鎖超時(shí)時(shí)間為1分鐘
Boolean result = redisTemplate.opsForValue().setIfAbsent(key, value, NX, timeUnit);
return result != null && result;
}
// unlock方法未測試,請測試后再使用
public void unlock(String key, String value) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('del', KEYS[1]) " +
"else " +
"return 0 " +
"end";
redisTemplate.execute((RedisCallback<Boolean>) connection -> {
Object nativeConnection = connection.getNativeConnection();
if (nativeConnection instanceof Jedis) {
return ((Jedis) nativeConnection).eval(script, Collections.singletonList(key), Collections.singletonList(value)).equals(1L);
} else if (nativeConnection instanceof RedisClusterConnection) {
return ((RedisClusterConnection) nativeConnection).eval(script.getBytes(), ReturnType.INTEGER, 1, key.getBytes(), value.getBytes()).equals(1L);
}
return false;
});
}
}
3.2 方法調(diào)用
public boolean getVerfityCode(String mobile) {
String smsCode = ShareCodeUtils.smsCode();
// redis鎖參數(shù)
String lockKey = "sms_lock_" + mobile;
String lockValue = UUID.randomUUID().toString();
boolean send = false;
try {
if (redisLock.tryLock(lockKey, lockValue)) {
// 獲取鎖成功,觸發(fā)短信驗(yàn)證碼功能(具體邏輯,此處因原登錄邏輯需要redis支持,故保留)
String s = redisUtils.get(RedisKeys.VERFITY_CODE + mobile);
if (s != null) {
// 判斷驗(yàn)證碼是否過期
throw new ServiceException("驗(yàn)證碼未過期,請勿重復(fù)獲取");
}
// 發(fā)送驗(yàn)證碼
send = smsBaoUtil.sendSms(mobile, smsCode);
if (send) {
// reids 中不存在 此電話對應(yīng)驗(yàn)證碼證明已經(jīng)過了 verCodeTm 秒,則可以重新生成
redisUtils.set(RedisKeys.VERFITY_CODE + mobile, smsCode, verCodeTm);
}
}
} catch (Exception e) {
send = false;
}
// 很多帖子這里會(huì)增加finally解鎖邏輯,這里為了保證1分鐘內(nèi)不會(huì)再觸發(fā)短信惡意調(diào)用,取消解鎖邏輯,由redis超時(shí)銷毀后,自動(dòng)解鎖。
return send;
}到此這篇關(guān)于redis防止短信惡意調(diào)用的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)redis防止短信惡意調(diào)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React實(shí)現(xiàn)組件之間通信的幾種常用方法
在?React?中,組件之間的通信是構(gòu)建復(fù)雜應(yīng)用程序的核心部分,良好的組件間通信能夠提高代碼的可維護(hù)性和可讀性,同時(shí)能夠高效地管理應(yīng)用狀態(tài),在這篇博客中,我們將探討?React中幾種常用的組件通信方法,并提供示例代碼來幫助你理解,需要的朋友可以參考下2025-02-02
Redis做預(yù)定庫存緩存功能設(shè)計(jì)使用
這篇文章主要為大家介紹了Redis做預(yù)定庫存緩存功能設(shè)計(jì)使用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
Redis內(nèi)存空間占用及避免數(shù)據(jù)丟失的方法
在現(xiàn)代的互聯(lián)網(wǎng)應(yīng)用中,Redis作為一種高性能的內(nèi)存數(shù)據(jù)庫,被廣泛應(yīng)用于緩存、會(huì)話管理和消息隊(duì)列等場景,然而,Redis的內(nèi)存資源是有限的,過多的內(nèi)存占用可能會(huì)導(dǎo)致數(shù)據(jù)丟失所以本文將給大家介紹一下Redis內(nèi)存空間占用及避免數(shù)據(jù)丟失的方法2023-08-08
Redis自動(dòng)化安裝及集群實(shí)現(xiàn)搭建過程
這篇文章主要介紹了Redis自動(dòng)化安裝以及集群實(shí)現(xiàn)搭建過程,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09
Redis和springboot 整合redisUtil類的示例代碼
這篇文章主要介紹了Redis和springboot 整合redisUtil類的示例代碼,本文通過實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
Redis密碼設(shè)置與訪問限制實(shí)現(xiàn)方法
這篇文章主要介紹了Redis密碼設(shè)置與訪問限制實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11

