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 配置類
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)文章
Maven添加Tomcat插件實(shí)現(xiàn)熱部署代碼實(shí)例
這篇文章主要介紹了Maven添加Tomcat插件實(shí)現(xiàn)熱部署代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
淺談Java中浮點(diǎn)型數(shù)據(jù)保留兩位小數(shù)的四種方法
今天在進(jìn)行開(kāi)發(fā)的過(guò)程中遇到了一個(gè)小問(wèn)題,是關(guān)于如何將double類型的數(shù)據(jù)保留兩位小數(shù)。具有一定的參考價(jià)值,本文就詳細(xì)的介紹一下2021-09-09
Java中常見(jiàn)的查找算法與排序算法總結(jié)
數(shù)據(jù)結(jié)構(gòu)是數(shù)據(jù)存儲(chǔ)的方式,算法是數(shù)據(jù)計(jì)算的方式。所以在開(kāi)發(fā)中,算法和數(shù)據(jù)結(jié)構(gòu)息息相關(guān)。本文為大家整理了Java中常見(jiàn)的查找與排序算法的實(shí)現(xiàn),需要的可以參考一下2023-03-03
如何基于LoadingCache實(shí)現(xiàn)Java本地緩存
這篇文章主要介紹了如何基于LoadingCache實(shí)現(xiàn)Java本地緩存,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12

