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ú)限制,僅通過(guò)redis保留驗(yàn)證碼發(fā)送信息。一個(gè)時(shí)間戳產(chǎn)生數(shù)次甚至十幾次調(diào)用,多個(gè)線程同時(shí)訪問(wèn)redis后,取值相同,均通過(guò)驗(yàn)證前往調(diào)用短信接口。
3.解決方案
使用redis分布式鎖,解決該問(wèn)題。
相關(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í)間單位為T(mén)imeUnit,并非大多帖子中表述的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)證碼是否過(guò)期 throw new ServiceException("驗(yàn)證碼未過(guò)期,請(qǐng)勿重復(fù)獲取"); } // 發(fā)送驗(yàn)證碼 send = smsBaoUtil.sendSms(mobile, smsCode); if (send) { // reids 中不存在 此電話對(duì)應(yīng)驗(yàn)證碼證明已經(jīng)過(guò)了 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í)銷(xiāo)毀后,自動(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)閃退問(wèn)題
本文主要介紹了完美解決Redis在雙擊redis-server.exe出現(xiàn)閃退問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01Spark刪除redis千萬(wàn)級(jí)別set集合數(shù)據(jù)實(shí)現(xiàn)分析
這篇文章主要為大家介紹了Spark刪除redis千萬(wàn)級(jí)別set集合數(shù)據(jù)實(shí)現(xiàn)過(guò)程分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06一起raid數(shù)據(jù)恢復(fù)及回遷成功的案例
這篇文章主要介紹了一起raid數(shù)據(jù)恢復(fù)及回遷成功的案例,需要的朋友可以參考下2017-04-04redis使用zset實(shí)現(xiàn)延時(shí)隊(duì)列的示例代碼
本文主要介紹了redis使用zset實(shí)現(xiàn)延時(shí)隊(duì)列的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06redis中使用bloomfilter的白名單功能解決緩存穿透問(wèn)題
本文主要介紹了redis中使用bloomfilter的白名單功能解決緩存穿透問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07redis 限制內(nèi)存使用大小的實(shí)現(xiàn)
這篇文章主要介紹了redis 限制內(nèi)存使用大小的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05redis執(zhí)行l(wèi)ua腳本的實(shí)現(xiàn)
本文主要介紹了redis執(zhí)行l(wèi)ua腳本的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-10-10