redis防止短信惡意調(diào)用的實(shí)現(xiàn)
1.場(chǎng)景
登錄或注冊(cè)接口中,使用短信驗(yàn)證碼場(chǎng)景時(shí),遇到惡意調(diào)用短信接口,一毫秒多次調(diào)用,導(dǎo)致短信資源大幅度消耗。
2.排查
經(jīng)排查發(fā)現(xiàn),短信發(fā)送接口無(wú)限制,僅通過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方法未測(cè)試,請(qǐng)測(cè)試后再使用
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)證碼未過期,請(qǐng)勿重復(fù)獲取");
}
// 發(fā)送驗(yàn)證碼
send = smsBaoUtil.sendSms(mobile, smsCode);
if (send) {
// reids 中不存在 此電話對(duì)應(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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
完美解決Redis在雙擊redis-server.exe出現(xiàn)閃退問題
本文主要介紹了完美解決Redis在雙擊redis-server.exe出現(xiàn)閃退問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01
Spark刪除redis千萬(wàn)級(jí)別set集合數(shù)據(jù)實(shí)現(xiàn)分析
這篇文章主要為大家介紹了Spark刪除redis千萬(wàn)級(jí)別set集合數(shù)據(jù)實(shí)現(xiàn)過程分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
一起raid數(shù)據(jù)恢復(fù)及回遷成功的案例
這篇文章主要介紹了一起raid數(shù)據(jù)恢復(fù)及回遷成功的案例,需要的朋友可以參考下2017-04-04
redis使用zset實(shí)現(xiàn)延時(shí)隊(duì)列的示例代碼
本文主要介紹了redis使用zset實(shí)現(xiàn)延時(shí)隊(duì)列的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
redis中使用bloomfilter的白名單功能解決緩存穿透問題
本文主要介紹了redis中使用bloomfilter的白名單功能解決緩存穿透問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
redis 限制內(nèi)存使用大小的實(shí)現(xiàn)
這篇文章主要介紹了redis 限制內(nèi)存使用大小的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05
redis執(zhí)行l(wèi)ua腳本的實(shí)現(xiàn)
本文主要介紹了redis執(zhí)行l(wèi)ua腳本的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-10-10

