本周收到一个优化请求,是对一个web项目实现登录用户的安全性校验,也就是实现登录次数的限制以及重试次数用完之后间隔时间再次恢复登录的功能。
一、何为spring-data-redis?
详情可以直接访问官网:https://spring.io/projects/spring-data-redis
1)概述
Spring Data Redis 是更大的 Spring Data 系列的一部分,它提供了从 Spring 应用程序对 Redis 的轻松配置和访问。它提供了与商店交互的低级和高级抽象,使用户摆脱了对基础设施的担忧。
2)功能用到的部分特征
- RedisTemplate为执行各种 Redis 操作、异常翻译和序列化支持提供高级抽象。
- 原子计数器支持类。
3)maven 引入
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
二、实现思路及其实现
1)需求逻辑
用户登录,用户名或密码错误,失败次数+1;当达到设定登录最大次数,提示还有多久才能再次尝试,会有一个冻结时间。中间即使用户名密码正确,也不让进入系统。
2)需要用到的一些变量:
/**
* 时间间隔(分钟)
*/privatestaticfinalint TIME_INTERVAL=1;/**
* 登录失败重试次数上限
*/privatestaticfinalint FAILED_RETRY_TIMES=6;/**
* 冻结时间 单位:秒
*/privatestaticfinalint FREEZE_TIME=5;/**
* redis记录用户登录失败次数key
*/privatestaticfinalString USER_LOGIN_FAILED_COUNT="USER:LOGIN:FAILED:COUNT:";
3)核心代码
/**
* 剩余次数操作
* @param key
* @return
*/privateRedisAtomicIntegergetRedisCounter(String key){RedisAtomicInteger counter=newRedisAtomicInteger(key, stringRedisTemplate.getConnectionFactory());if(counter.get()==0){
counter.expire(TIME_INTERVAL,TimeUnit.MINUTES);}return counter;}/**
* 过期时间设置
* @param key
*/privatevoidgetRedisExpireTime(String key){
stringRedisTemplate.opsForValue().set(key,key,FREEZE_TIME,TimeUnit.MINUTES);}
// 访问次数keyString key= USER_LOGIN_FAILED_COUNT+ username;//冻结时间keyString keyTime= USER_LOGIN_FAILED_COUNT+ username+ FREEZE_TIME;//获取计数时间RedisAtomicInteger counter=getRedisCounter(key);//查看冻结时间,进行判定Long expireTime= stringRedisTemplate.boundHashOps(keyTime).getExpire();if(counter.get()>= FAILED_RETRY_TIMES&& expireTime>0){returnResultResponse.ofError("登录次数已达上线,请"+ stringRedisTemplate.getExpire(keyTime,TimeUnit.MINUTES)+"分钟之后重试");}/ matchResult 对密码的逻辑校验// 密码不正确if(!matchResult){String message;Integer remainingTimes= FAILED_RETRY_TIMES- counter.get();if(remainingTimes>0){if(remainingTimes.equals(FAILED_RETRY_TIMES)){
message="密码错误";
counter.getAndIncrement();}else{
message="密码错误,剩余重试次数"+(FAILED_RETRY_TIMES- counter.get())+"次";
counter.getAndIncrement();}}else{if(!stringRedisTemplate.hasKey(keyTime)){getRedisExpireTime(keyTime);}
message="账户被锁定,请"+ stringRedisTemplate.getExpire(keyTime,TimeUnit.MINUTES)+"分钟之后重试";}returnResultResponse.ofMessage(-1, message);}
三、实现效果展示
用户登录次数限制效果展示