SpringBoot整合Redis實(shí)現(xiàn)登錄失敗鎖定功能(實(shí)例詳解)
前言
在現(xiàn)代的軟件開發(fā)中,安全性和用戶體驗(yàn)是至關(guān)重要的方面。特別是在身份驗(yàn)證和授權(quán)方面,保護(hù)用戶賬戶免受惡意訪問是至關(guān)重要的。一種常見的安全措施是通過限制登錄失敗的嘗試次數(shù)來防止暴力破解攻擊。這意味著如果用戶連續(xù)多次輸入錯(cuò)誤的憑據(jù),系統(tǒng)將暫時(shí)禁止其登錄,以防止進(jìn)一步的嘗試。
在本博客中,我們將探討如何利用Redis來實(shí)現(xiàn)這樣的安全措施。具體來說,我們將學(xué)習(xí)如何在用戶連續(xù)多次登錄失敗后,暫時(shí)將其賬戶鎖定一段時(shí)間(例如一分鐘),以確保系統(tǒng)的安全性和用戶體驗(yàn)。通過結(jié)合Spring Boot的便利性和Redis的高效性,我們能夠輕松實(shí)現(xiàn)這一功能,提高系統(tǒng)的安全性,同時(shí)確保用戶友好的體驗(yàn)。讓我們深入探討這個(gè)案例,并了解如何在Spring Boot應(yīng)用中實(shí)現(xiàn)這一重要功能。
一、為何選擇Redis作為賬戶鎖定的存儲(chǔ)解決方案?
在實(shí)現(xiàn)登錄失敗次數(shù)過多時(shí)的賬戶鎖定功能時(shí),選擇適當(dāng)?shù)臄?shù)據(jù)存儲(chǔ)解決方案至關(guān)重要。Redis作為一個(gè)高性能的內(nèi)存數(shù)據(jù)庫,提供了一系列特性,使其成為這一場(chǎng)景的理想選擇。
- 快速的讀寫操作:Redis以內(nèi)存為基礎(chǔ),能夠快速執(zhí)行讀寫操作,特別適用于需要頻繁更新的計(jì)數(shù)場(chǎng)景。這意味著我們能夠迅速地記錄用戶的登錄失敗次數(shù),并實(shí)時(shí)更新賬戶的鎖定狀態(tài)。
- 原子性操作: Redis支持原子性操作,能夠確保在多線程或多進(jìn)程環(huán)境下,對(duì)數(shù)據(jù)的讀寫操作是線程安全的。這對(duì)于確保登錄失敗次數(shù)的準(zhǔn)確性和賬戶鎖定的可靠性至關(guān)重要。
- 過期時(shí)間設(shè)置: Redis允許我們?yōu)榇鎯?chǔ)的數(shù)據(jù)設(shè)置過期時(shí)間,這非常有利于實(shí)現(xiàn)一定時(shí)間內(nèi)的賬戶鎖定。例如,我們可以設(shè)置一個(gè)一分鐘的過期時(shí)間,讓用戶在一定時(shí)間后自動(dòng)解鎖。
- 靈活的數(shù)據(jù)結(jié)構(gòu): Redis支持多種數(shù)據(jù)結(jié)構(gòu),包括字符串、哈希、列表等,這使得我們能夠更靈活地存儲(chǔ)和管理與賬戶鎖定相關(guān)的信息,而不僅僅局限于簡(jiǎn)單的計(jì)數(shù)。
- 持久性選項(xiàng): 雖然Redis以內(nèi)存為主,但它也支持持久性選項(xiàng),可以將數(shù)據(jù)持久化到磁盤,以防止數(shù)據(jù)丟失。這對(duì)于一些安全敏感的場(chǎng)景是一個(gè)備用的選項(xiàng)。
總的來說,Redis的快速性能、原子性操作、過期時(shí)間設(shè)置和靈活的數(shù)據(jù)結(jié)構(gòu)使其成為實(shí)現(xiàn)登錄失敗次數(shù)過多時(shí)的賬戶鎖定功能的優(yōu)秀選擇。在結(jié)合Spring Boot的便捷性和Redis的高效性時(shí),我們能夠輕松而可靠地增加系統(tǒng)的安全性
二、代碼案例講解
1.引入依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <version>8.0.31</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.3</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.28</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>2.5.9</version> </dependency>
2.配置文件
# 數(shù)據(jù)庫驅(qū)動(dòng): spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # 數(shù)據(jù)庫連接地址 spring.datasource.url=jdbc:mysql://localhost:3306/數(shù)據(jù)庫?serverTimezone=UTC # 數(shù)據(jù)庫用戶名&密碼: spring.datasource.username=用戶名 spring.datasource.password=密碼 spring.main.allow-circular-references=true # redis地址 spring.redis.host=localhost spring.redis.port=6379
3.示例代碼
實(shí)體類代碼:
@TableName(value ="phone") @AllArgsConstructor @NoArgsConstructor @Data public class Phone implements Serializable { /** * */ @TableId(type = IdType.AUTO) private Integer id; /** * */ private String number; /** * */ private String password;
controller層代碼:
// 記錄登錄失敗次數(shù) 登錄失敗次數(shù)大于5次 限制登錄一分鐘 @RequestMapping("relogin") public String relogin(String number,String password) { String key = "login:"; String loginkey="fail"+number; LambdaQueryWrapper<Phone> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(Phone::getNumber,number); queryWrapper.eq(Phone::getPassword,password); Phone phones = phoneService.getOne(queryWrapper); if (phones!=null){ redisTemplate.delete(key); redisTemplate.delete(loginkey); return "登陸成功"; } redisTemplate.opsForValue().increment(key); redisTemplate.expire(key,1,TimeUnit.MINUTES); redisTemplate.opsForValue().set(loginkey, String.valueOf(System.currentTimeMillis()),1,TimeUnit.MINUTES); String loginNumStr = redisTemplate.opsForValue().get(key); Integer loginNum = (loginNumStr != null) ? Integer.parseInt(loginNumStr) : 0; if (loginNum != null && loginNum >= 5) { long localtime = System.currentTimeMillis(); long failtime = Long.parseLong(redisTemplate.opsForValue().get(loginkey)); long time = localtime - failtime; if(time<60000){ return "您的登錄失敗次數(shù)已經(jīng)至少5次,請(qǐng)一分鐘后重試"; } } return "登陸失敗"; }
下面我來逐步解釋代碼的功能和邏輯:
- 首先,方法的簽名是 relogin(String number, String password),表明它接收一個(gè)手機(jī)號(hào)碼和密碼作為輸入?yún)?shù)。
- 在方法內(nèi)部,首先定義了兩個(gè)字符串變量:key 和 loginkey。key 的值是 “login:”,loginkey 的值是 “fail” 加上用戶提供的手機(jī)號(hào)碼。
- 使用 Lambda 表達(dá)式創(chuàng)建了一個(gè)查詢條件 LambdaQueryWrapper queryWrapper,用于查詢數(shù)據(jù)庫中是否存在指定手機(jī)號(hào)碼和密碼的用戶記錄。
- 執(zhí)行查詢操作 phoneService.getOne(queryWrapper),將結(jié)果存儲(chǔ)在 phones 變量中。
- 如果查詢結(jié)果不為 null(即找到了匹配的用戶記錄),則執(zhí)行以下操作:
- 刪除 Redis 中存儲(chǔ)的與登錄相關(guān)的鍵值對(duì),包括 key 和 loginkey。
- 返回字符串 “登陸成功”。
- 如果查詢結(jié)果為 null(未找到匹配的用戶記錄),則執(zhí)行以下操作:
- 使用 Redis 記錄登錄失敗次數(shù)。通過遞增 key 對(duì)應(yīng)的值,記錄當(dāng)前登錄失敗的次數(shù)并且設(shè)置過期時(shí)間為一分鐘。
- 使用 Redis 存儲(chǔ)登錄失敗的時(shí)間戳,以便后續(xù)檢查登錄失敗次數(shù)是否達(dá)到上限。
- 通過獲取 key 對(duì)應(yīng)的值,檢查當(dāng)前登錄失敗的次數(shù)。如果登錄失敗次數(shù)達(dá)到或超過 5 次,進(jìn)入以下判斷:
- 獲取當(dāng)前時(shí)間和最近一次登錄失敗的時(shí)間之間的時(shí)間差 time。
- 如果時(shí)間差小于 60000 毫秒(即一分鐘),則返回提示信息:“您的登錄失敗次數(shù)已經(jīng)超過5次,請(qǐng)一分鐘后重試”。
- 如果以上條件都不滿足,則返回 “登陸失敗”。
總結(jié)
在本博客中,我們已經(jīng)探討如何利用Redis來實(shí)現(xiàn)鎖定賬戶的安全措施,以及通過SpringBoot整合Redis實(shí)現(xiàn)了這一功能。具體的高級(jí)用法還需小伙伴們?nèi)ド钊胙芯俊?/p>
到此這篇關(guān)于SpringBoot整合Redis實(shí)現(xiàn)登錄失敗鎖定功能的文章就介紹到這了,更多相關(guān)SpringBoot Redis登錄失敗鎖定內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
啟動(dòng)SpringBoot報(bào)JavaMail加載錯(cuò)誤的原因分析和解決
這篇文章給大家介紹了啟動(dòng)SpringBoot報(bào)JavaMail加載錯(cuò)誤的原因分析和解決,文中通過代碼示例給出了詳細(xì)的原因分析和解決方法,對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-01-01ssm框架controller層返回json格式數(shù)據(jù)到頁面的實(shí)現(xiàn)
這篇文章主要介紹了ssm框架controller層返回json格式數(shù)據(jù)到頁面的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09解決Springboot項(xiàng)目bootstrap.yml不生效問題
Spring Boot 2.4版本開始,配置文件加載方式進(jìn)行了重構(gòu),只會(huì)識(shí)別application.* 配置文件,并不會(huì)自動(dòng)識(shí)別bootstrap.yml,所以本文給大家介紹Springboot項(xiàng)目bootstrap.yml不生效問題的解決方案,需要的朋友可以參考下2023-09-09Springboot項(xiàng)目基于Devtools實(shí)現(xiàn)熱部署步驟詳解
這篇文章主要介紹了Springboot項(xiàng)目基于Devtools實(shí)現(xiàn)熱部署,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06MyBatis源碼解析——獲取SqlSessionFactory方式
這篇文章主要介紹了MyBatis源碼解析——獲取SqlSessionFactory方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12