SpringBoot整合redis并实现输入密码错误限制登录功能

需求:
实现一个登录功能,并且2分钟之内只能输入5次错误密码,若输入五次之后还没有输入正确密码,系统将会将该账号锁定1小时

pom.xml

 
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-devtools
            runtime
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        


        
        
            redis.clients
            jedis
            3.1.0
        

        
            org.springframework.boot
            spring-boot-starter-data-redis
        









        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
    

yml配置

#redis
redis:
  #redis机器ip
  hostname: 127.0.0.1
  #redis端口
  port: 6379
  #redis密码
  password:
  #redis超时时间(毫秒),如果不设置,取默认值2000
  timeout: 10000
  #最大空闲数
  maxIdle: 300
  #连接池的最大数据库连接数。设为0表示无限制,如果是jedis 2.4以后用redis.maxTotal
  #maxActive=600
  #控制一个pool可分配多少个jedis实例,用来替换上面的redis.maxActive,如果是jedis 2.4以后用该属性
  maxTotal: 1000
  #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
  maxWaitMillis: 1000
  #连接的最小空闲时间 默认1800000毫秒(30分钟)
  minEvictableIdleTimeMillis: 300000
  #每次释放连接的最大数目,默认3
  numTestsPerEvictionRun: 1024
  #逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
  timeBetweenEvictionRunsMillis: 30000
  #是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
  testOnBorrow: true
  #在空闲时检查有效性, 默认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 redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory) {
        RedisTemplate 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 map = loginService.loginUserLock(user);   //登录 验证第一层  看用户是否被限制登录

        if ((Boolean) map.get("flag")) {   //如果为true表示被限制登录
            return "登录失败,因" + username + "超过了限制登录次数,已被禁止登录.还剩" + map.get("lockTime") + "分钟";

        } else {   //表示没有被限制登录   执行 下一步登录逻辑

            User user1 = loginService.login(user);  //执行登录功能

            if (user1 != null) {   //表示密码正确  登录成功
                /**
                 * 清空对应的所有key
                 */
                loginService.DeleteMemory(getMessage.getLoginCountFailKey(user));
                loginService.DeleteMemory(getMessage.getLoginTimeLockKey(user));
                loginService.DeleteMemory(getMessage.getKeyName(user));

                return "登录成功";
            } else {  //登录不成功   计入登录此时 等逻辑操作
                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 {
    /**
     * 验证用户登录的账号和密码
     * @param user
     * @return
     */
    User login(User user);

    /**
     * 用户在2分钟内 仅允许输入错误密码五次,如果超过次数,限制其登录一小时
     *
     * 给用户详细信息提示
     * @param user
     * @return
     */
    String loginValdata(User user);

    /**
     * 判断当前的登录用户是否被限制登录
     * @param user
     * @return
     */
    Map loginUserLock(User user);

    /**
     * 登录不成功的操作(密码错误)
     * @param user
     * @return
     */
    String loginValdate(User user);

    /**
     * 删除登录失败所存入的键值对
     * @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;

    /**
     * 验证用户是密码是否正确
     *
     * @param user
     * @return
     */
    @Override
    public User login(User user) {
        if (user.getUsername().equals("dlf")) {      //模仿从数据库中根据username查询密码  然后验证密码是否正确
            if (user.getPassword().equals("dlf")) {
                return user;
            }
        }
        return null;
    }

    @Override
    public String loginValdata(User user) {
        return null;
    }

    /**
     * 判断当前登录的用户是否被限制登录
     * 查询当前key是否存在,如果存在,就被限制,注意:需要给用户做提示:您当前的用户已被限制,还剩多长时间
     * 如果不存在就不被限制
     *
     * @param user
     * @return
     */
    @Override
    public Map loginUserLock(User user) {
        Map map = new HashMap<>();
        if (stringRedisTemplate.hasKey(getMessage.getLoginTimeLockKey(user))) {
            //如果存在就是用户已经输错了密码五次 被锁定了俩小时
            map.put("flag", true);  //表示用户已经被锁定
            map.put("lockTime", stringRedisTemplate.getExpire(getMessage.getLoginTimeLockKey(user), TimeUnit.MINUTES));     //得到被锁定之后还剩下多少时间  以分钟返回
        } else {
            map.put("flag", false);   //flag 为false 表示用户没有被限制
        }
        return map;
    }


    /**
     * 登录失败的相应操作(密码错误)
     *
     * @param user
     * @return
     */

    @Override
    public String loginValdate(User user) {

        Integer num = 5;
        //记录登录错误次数的key
        String key = getMessage.getLoginCountFailKey(user);
        if (!stringRedisTemplate.hasKey(key)) {   //如果不存在
            //是第一次登录失败 次数为1
            // userlogincountfile;用户名进行赋值   同时设置失效期2分钟
            stringRedisTemplate.opsForValue().set(key, "1", 2, TimeUnit.MINUTES);
            return "登录失败,在2分钟内还允许输入错误" + (num - 1) + "次";
        } else {
            //如果存在
            //查询登录失败次数
            long loginFilCount = Long.parseLong(stringRedisTemplate.opsForValue().get(key));
            if (loginFilCount < (num - 1)) {    //代表当前如果登录次数小于4  意思:还有资格继续进行登录
                //登录次数+1
                stringRedisTemplate.opsForValue().increment(key, 1);
                long secends = stringRedisTemplate.getExpire(key, TimeUnit.SECONDS);  //返回的是秒
                return user.getUsername() + "登录失败,在" + secends + "秒内还允许输入错误" + (num - loginFilCount - 1) + "次";
            } else {   //超过了指定的登录次数
                String lockkey = getMessage.getLoginTimeLockKey(user);
                stringRedisTemplate.opsForValue().set(lockkey, "1", 1, TimeUnit.HOURS);
                return "因登录失败此时超过" + num + "次,以对其限制登录1小时";
            }
        }
    }

    @Override
    public Boolean DeleteMemory(String key) {
        try {
            stringRedisTemplate.delete(key);
        } catch (Exception e) {
            return false;
        }
        return true;
    }


}

你可能感兴趣的:(shiro,SpringBoot)