SpringBoot整合redis實(shí)現(xiàn)輸入密碼錯(cuò)誤限制登錄功能
需求:
實(shí)現(xiàn)一個(gè)登錄功能,并且2分鐘之內(nèi)只能輸入5次錯(cuò)誤密碼,若輸入五次之后還沒(méi)有輸入正確密碼,系統(tǒng)將會(huì)將該賬號(hào)鎖定1小時(shí)
pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- jedis 包--> <!-- https://mvnrepository.com/artifact/redis.clients/jedis --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.1.0</version> </dependency> <!--springboot整合redis包--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- <dependency>--> <!-- <groupId>org.springframework.boot</groupId>--> <!-- <artifactId>spring-boot-configuration-processor</artifactId>--> <!-- <optional>true</optional>--> <!-- </dependency>--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> </dependencies>
yml配置
#redis redis: #redis機(jī)器ip hostname: 127.0.0.1 #redis端口 port: 6379 #redis密碼 password: #redis超時(shí)時(shí)間(毫秒),如果不設(shè)置,取默認(rèn)值2000 timeout: 10000 #最大空閑數(shù) maxIdle: 300 #連接池的最大數(shù)據(jù)庫(kù)連接數(shù)。設(shè)為0表示無(wú)限制,如果是jedis 2.4以后用redis.maxTotal #maxActive=600 #控制一個(gè)pool可分配多少個(gè)jedis實(shí)例,用來(lái)替換上面的redis.maxActive,如果是jedis 2.4以后用該屬性 maxTotal: 1000 #最大建立連接等待時(shí)間。如果超過(guò)此時(shí)間將接到異常。設(shè)為-1表示無(wú)限制。 maxWaitMillis: 1000 #連接的最小空閑時(shí)間 默認(rèn)1800000毫秒(30分鐘) minEvictableIdleTimeMillis: 300000 #每次釋放連接的最大數(shù)目,默認(rèn)3 numTestsPerEvictionRun: 1024 #逐出掃描的時(shí)間間隔(毫秒) 如果為負(fù)數(shù),則不運(yùn)行逐出線程, 默認(rèn)-1 timeBetweenEvictionRunsMillis: 30000 #是否在從池中取出連接前進(jìn)行檢驗(yàn),如果檢驗(yàn)失敗,則從池中去除連接并嘗試取出另一個(gè) testOnBorrow: true #在空閑時(shí)檢查有效性, 默認(rèn)false testWhileIdle: true #redis集群配置 #spring.cluster.nodes=192.168.1.1:7001,192.168.1.1:7002,192.168.1.1:7003,192.168.1.1:7004,192.168.1.1:7005,192.168.1.1:7006 #spring.cluster.max-redirects=3 #哨兵模式 #sentinel.host1=192.168.1.1 #sentinel.port1=26379 #sentinel.host2=192.168.1.2 #sentinel.port2=26379 spring: thymeleaf: cache: false prefix: classpath:/templates/ suffix: .html encoding: UTF-8 mode: HTML5 servlet:
bean層:
package com.springbootandredis.springbootredis.bean; public class User { String username; String password; public User() { } public User(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
config 配置類(lèi)
package com.springbootandredis.springbootredis.config; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import java.io.Serializable; @Configuration @AutoConfigureAfter(RedisAutoConfiguration.class) public class RedisConfig { @Bean public RedisTemplate<String, Serializable> redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory) { RedisTemplate<String, Serializable> template = new RedisTemplate<>(); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); template.setConnectionFactory(redisConnectionFactory); return template; } }
controller
package com.springbootandredis.springbootredis.controller; import com.springbootandredis.springbootredis.Service.ServiceImpl.GetMessageImpl; import com.springbootandredis.springbootredis.Service.ServiceImpl.LoginServiceImpl; import com.springbootandredis.springbootredis.bean.User; import org.hibernate.validator.constraints.pl.REGON; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; import java.util.Map; @Controller public class userlogin { @Autowired LoginServiceImpl loginService; @Autowired GetMessageImpl getMessage; @ResponseBody @RequestMapping("/login") public String login(HttpServletRequest request) { String username = request.getParameter("username"); String password = request.getParameter("password"); User user = new User(username, password); Map<String, Object> map = loginService.loginUserLock(user); //登錄 驗(yàn)證第一層 看用戶是否被限制登錄 if ((Boolean) map.get("flag")) { //如果為true表示被限制登錄 return "登錄失敗,因" + username + "超過(guò)了限制登錄次數(shù),已被禁止登錄.還剩" + map.get("lockTime") + "分鐘"; } else { //表示沒(méi)有被限制登錄 執(zhí)行 下一步登錄邏輯 User user1 = loginService.login(user); //執(zhí)行登錄功能 if (user1 != null) { //表示密碼正確 登錄成功 /** * 清空對(duì)應(yīng)的所有key */ loginService.DeleteMemory(getMessage.getLoginCountFailKey(user)); loginService.DeleteMemory(getMessage.getLoginTimeLockKey(user)); loginService.DeleteMemory(getMessage.getKeyName(user)); return "登錄成功"; } else { //登錄不成功 計(jì)入登錄此時(shí) 等邏輯操作 return loginService.loginValdate(user); } } } @RequestMapping("/tologin") public String tologin() { return "login"; } }
service interface
package com.springbootandredis.springbootredis.Service; import com.springbootandredis.springbootredis.bean.User; public interface GetMessage { String getKeyName(User user); String getLoginTimeLockKey(User user); String getLoginCountFailKey(User user); } /************分界線***********************************/ package com.springbootandredis.springbootredis.Service; import com.springbootandredis.springbootredis.bean.User; import java.util.Map; public interface LoginService { /** * 驗(yàn)證用戶登錄的賬號(hào)和密碼 * @param user * @return */ User login(User user); /** * 用戶在2分鐘內(nèi) 僅允許輸入錯(cuò)誤密碼五次,如果超過(guò)次數(shù),限制其登錄一小時(shí) * * 給用戶詳細(xì)信息提示 * @param user * @return */ String loginValdata(User user); /** * 判斷當(dāng)前的登錄用戶是否被限制登錄 * @param user * @return */ Map<String,Object> loginUserLock(User user); /** * 登錄不成功的操作(密碼錯(cuò)誤) * @param user * @return */ String loginValdate(User user); /** * 刪除登錄失敗所存入的鍵值對(duì) * @param key * @return */ Boolean DeleteMemory(String key); }
service impl
package com.springbootandredis.springbootredis.Service.ServiceImpl; import com.springbootandredis.springbootredis.Service.GetMessage; import com.springbootandredis.springbootredis.bean.User; import org.springframework.stereotype.Service; @Service public class GetMessageImpl implements GetMessage { @Override public String getKeyName(User user) { return "user:"+user.getUsername(); } @Override public String getLoginTimeLockKey(User user) { return "user:loginTime:lock:"+user.getUsername(); } @Override public String getLoginCountFailKey(User user) { return "user:loginCount:fail:"+user.getUsername(); } } /******************************************分界線*************************************/ package com.springbootandredis.springbootredis.Service.ServiceImpl; import com.springbootandredis.springbootredis.Service.LoginService; import com.springbootandredis.springbootredis.bean.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import javax.validation.Valid; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; @Service public class LoginServiceImpl implements LoginService { @Autowired GetMessageImpl getMessage; @Autowired StringRedisTemplate stringRedisTemplate; /** * 驗(yàn)證用戶是密碼是否正確 * * @param user * @return */ @Override public User login(User user) { if (user.getUsername().equals("dlf")) { //模仿從數(shù)據(jù)庫(kù)中根據(jù)username查詢密碼 然后驗(yàn)證密碼是否正確 if (user.getPassword().equals("dlf")) { return user; } } return null; } @Override public String loginValdata(User user) { return null; } /** * 判斷當(dāng)前登錄的用戶是否被限制登錄 * 查詢當(dāng)前key是否存在,如果存在,就被限制,注意:需要給用戶做提示:您當(dāng)前的用戶已被限制,還剩多長(zhǎng)時(shí)間 * 如果不存在就不被限制 * * @param user * @return */ @Override public Map<String, Object> loginUserLock(User user) { Map<String, Object> map = new HashMap<>(); if (stringRedisTemplate.hasKey(getMessage.getLoginTimeLockKey(user))) { //如果存在就是用戶已經(jīng)輸錯(cuò)了密碼五次 被鎖定了倆小時(shí) map.put("flag", true); //表示用戶已經(jīng)被鎖定 map.put("lockTime", stringRedisTemplate.getExpire(getMessage.getLoginTimeLockKey(user), TimeUnit.MINUTES)); //得到被鎖定之后還剩下多少時(shí)間 以分鐘返回 } else { map.put("flag", false); //flag 為false 表示用戶沒(méi)有被限制 } return map; } /** * 登錄失敗的相應(yīng)操作(密碼錯(cuò)誤) * * @param user * @return */ @Override public String loginValdate(User user) { Integer num = 5; //記錄登錄錯(cuò)誤次數(shù)的key String key = getMessage.getLoginCountFailKey(user); if (!stringRedisTemplate.hasKey(key)) { //如果不存在 //是第一次登錄失敗 次數(shù)為1 // userlogincountfile;用戶名進(jìn)行賦值 同時(shí)設(shè)置失效期2分鐘 stringRedisTemplate.opsForValue().set(key, "1", 2, TimeUnit.MINUTES); return "登錄失敗,在2分鐘內(nèi)還允許輸入錯(cuò)誤" + (num - 1) + "次"; } else { //如果存在 //查詢登錄失敗次數(shù) long loginFilCount = Long.parseLong(stringRedisTemplate.opsForValue().get(key)); if (loginFilCount < (num - 1)) { //代表當(dāng)前如果登錄次數(shù)小于4 意思:還有資格繼續(xù)進(jìn)行登錄 //登錄次數(shù)+1 stringRedisTemplate.opsForValue().increment(key, 1); long secends = stringRedisTemplate.getExpire(key, TimeUnit.SECONDS); //返回的是秒 return user.getUsername() + "登錄失敗,在" + secends + "秒內(nèi)還允許輸入錯(cuò)誤" + (num - loginFilCount - 1) + "次"; } else { //超過(guò)了指定的登錄次數(shù) String lockkey = getMessage.getLoginTimeLockKey(user); stringRedisTemplate.opsForValue().set(lockkey, "1", 1, TimeUnit.HOURS); return "因登錄失敗此時(shí)超過(guò)" + num + "次,以對(duì)其限制登錄1小時(shí)"; } } } @Override public Boolean DeleteMemory(String key) { try { stringRedisTemplate.delete(key); } catch (Exception e) { return false; } return true; } }
到此這篇關(guān)于SpringBoot整合redis并實(shí)現(xiàn)輸入密碼錯(cuò)誤限制登錄功能的文章就介紹到這了,更多相關(guān)SpringBoot redis輸入密碼錯(cuò)誤限制登錄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java concurrency之AtomicLongFieldUpdater原子類(lèi)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
AtomicLongFieldUpdater可以對(duì)指定"類(lèi)的 'volatile long'類(lèi)型的成員"進(jìn)行原子更新。它是基于反射原理實(shí)現(xiàn)的。下面通過(guò)本文給大家分享Java concurrency之AtomicLongFieldUpdater原子類(lèi)的相關(guān)知識(shí),感興趣的朋友一起看看吧2017-06-06自從在 IDEA 中用了熱部署神器 JRebel 之后,開(kāi)發(fā)效率提升了 10(真棒)
在javaweb開(kāi)發(fā)過(guò)程中,使用熱部署神器 JRebel可以使class類(lèi)還是更新spring配置文件都能立馬見(jiàn)到效率,本文給大家介紹JRebel的兩種安裝方法,小編建議使用第二種方法,具體安裝步驟跟隨小編一起看看吧2021-06-06IDEA-SpringBoot項(xiàng)目Debug啟動(dòng)不了(卡住不動(dòng))的原因分析
這篇文章主要介紹了IDEA-SpringBoot項(xiàng)目Debug啟動(dòng)不了(卡住不動(dòng))的原因分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11springboot實(shí)現(xiàn)過(guò)濾器的示例代碼
JavaWeb開(kāi)發(fā)中,過(guò)濾器Filter是三大組件之一,主要用于請(qǐng)求攔截和響應(yīng)處理,如權(quán)限校驗(yàn)、日志記錄、請(qǐng)求過(guò)濾等,本文就來(lái)介紹一下springboot實(shí)現(xiàn)過(guò)濾器的示例代碼,感興趣的可以了解一下2024-10-10java -jar啟動(dòng)項(xiàng)目以及日志輸出的相關(guān)問(wèn)題
這篇文章主要介紹了java -jar啟動(dòng)項(xiàng)目以及日志輸出的相關(guān)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04spring中前端明明傳了值后端卻接收不到問(wèn)題解決辦法
在學(xué)習(xí)Spring的時(shí)候遇到了一個(gè)問(wèn)題,后臺(tái)一直接收不到前臺(tái)傳遞過(guò)來(lái)的參數(shù),耽誤了好長(zhǎng)時(shí)間終于找到了原因,這篇文章主要給大家介紹了關(guān)于spring中前端明明傳了值后端卻接收不到問(wèn)題的解決辦法,需要的朋友可以參考下2024-05-05一篇文章帶你了解JAVA面對(duì)對(duì)象之繼承與修飾符
這篇文章主要介紹了Java面向?qū)ο缶幊讨?lèi)的繼承,結(jié)合實(shí)例形式較為詳細(xì)的分析了Java面向?qū)ο缶幊填?lèi)的概念、功能、使用方法及相關(guān)注意事項(xiàng),需要的朋友可以參考下2021-08-08spring使用ehcache實(shí)現(xiàn)頁(yè)面緩存示例
這篇文章主要介紹了spring使用ehcache實(shí)現(xiàn)頁(yè)面緩存示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02SpringBoot如何基于POI-tl和word模板導(dǎo)出龐大的Word文件
這篇文章主要介紹了SpringBoot如何基于POI-tl和word模板導(dǎo)出龐大的Word文件,poi-tl是一個(gè)基于Apache?POI的Word模板引擎,也是一個(gè)免費(fèi)開(kāi)源的Java類(lèi)庫(kù)2022-08-08