当前位置: 首页 > 工具软件 > Spring-Monkey > 使用案例 >

Spring-Data Redis 实现验证码的功能

薛弘壮
2023-12-01

Redis是一个 Key-Value 存储系统。和 Memcached 类似,它支持存储的 value 类型相对更多,包括 string(字符串)、 list(链表)、 set(集合)和 zset(有序集合)。这些数据类型都支持 push/pop、add/remove 及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,Redis 支持各种不同方式的排序。与 memcached 一样,为了保证效率,数据都是缓存在内存中。区别的是 Redis 会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了 master-slave(主从)同步


作者:Monkey_D_lufy
链接:http://www.jianshu.com/p/01b37cdb3f33
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

经过我 查找资料,这的确适合存储验证码,首先具有时间性,而且速度也是比较快
官网下载地址:https://redis.io/download
要使用redis 必须要电脑上安装redis,然后通过spring redis 连接redis,就可以使用。

我简单说下基于Centos 7 中 redis 的安装过程

1、wget http://download.redis.io/releases/redis-4.0.1.tar.gz

2、 tar xzf redis-4.0.1.tar
3、cd redis -4.0.1
4、make test
5、make install
6、vi redis.conf
修改bind 为0.0.0.0 代表所有人都可以访问

daemonize :yes

允许防火墙开启6379 

$ firewall-cmd --zone=public --add-port=6379/tcp --permanent

$ firewall-cmd --reload //重新载入

ps -ef |grep 6379

/usr/local/bin/redis-server *:6379 中通过"*"就可以看出此时是允许所有的ip连接登录到这台redis服务上

代码如下

在pom.xml 加入spring-data redis 的依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

如果你项目有spring-devtool 依赖,请注释掉,要不然redis会出问题的

<dependency>
   <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
</dependency>

编辑 application.yml 加入这两句就可以了

redis:
    host: 192.168.1.200
    port: 6379


其中在Spring 容器中 redis bean 只有一个,不管你在哪里注入,取的值都是这个实例中的 ,我使用

@Configuration
public class RedisConfig {



    public final Environment ev;

    public RedisConfig(Environment ev) {
        this.ev = ev;
    }

    @Bean
    JedisConnectionFactory jedisConnectionFactory() {
        JedisConnectionFactory jedisConnectionFactory=new JedisConnectionFactory();
        jedisConnectionFactory.setHostName(ev.getProperty("spring.redis.host"));
        jedisConnectionFactory.setPort(Integer.parseInt(ev.getProperty("spring.redis.port")));
        return jedisConnectionFactory;
  }

    @Bean
    RedisTemplate<String, RegisteredVM> redisTemplate() {
        RedisTemplate<String, RegisteredVM> template = new RedisTemplate<>();
        template.setConnectionFactory(jedisConnectionFactory());
        template.setKeySerializer(new StringRedisSerializer()); //代表key的值为String
        template.setValueSerializer(new JdkSerializationRedisSerializer());// 代表value的值为对象,当然这两个可以随意调换,
        //最好自己百度redis的序列化,会更加明白
        return template;
    }

}


@RestController
@RequestMapping("/api")
public class AccountResource {

    private final Logger log = LoggerFactory.getLogger(AccountResource.class);

    private final UserRepository userRepository;

    private final UserService userService;

    private final MailService mailService;

    @Autowired
    private RedisTemplate<String, RegisteredVM> redisTemplate;
    
    private List<String> sentType = Arrays.asList("register", "forgotPassword", "activate");

     //为了reidis支持不同情况的手机验证码只能存在一个,我在发送验证码加了type拼装,这样保证注册发送的验证码是唯一的,不会跟其他的发送类型的验证码冲突
    @PostMapping(path = "/register", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_PLAIN_VALUE})
    @Timed
public ResponseEntity registerAccount(@Valid @RequestBody ManagedUserVM managedUserVM,
                                      @RequestParam(required = false) String code) {
    HttpHeaders textPlainHeaders = new HttpHeaders();
    textPlainHeaders.setContentType(MediaType.TEXT_PLAIN);
    String type = "register";
    if (redisTemplate.opsForValue().get(managedUserVM.getLogin().toLowerCase() +","+ type) == null) {
        return new ResponseEntity<>("验证码不存在,请重新发送", textPlainHeaders, HttpStatus.BAD_REQUEST);
    } else {
        if (!redisTemplate.opsForValue().get(managedUserVM.getLogin() + "," + type).getCode().equals(code)) {
            return new ResponseEntity<>("验证码不正确,请重新输入", textPlainHeaders, HttpStatus.FORBIDDEN);
        }
    }
    if (!managedUserVM.getPassword().equals(managedUserVM.getRepeatPasswor())) {
        return new ResponseEntity<>("你的两次密码不正确,请重新输入", textPlainHeaders, HttpStatus.FORBIDDEN);
    }

    return userRepository.findOneByLogin(managedUserVM.getLogin())
        .map(user -> new ResponseEntity<>("login already in use", textPlainHeaders, HttpStatus.BAD_REQUEST))
            .orElseGet(() -> {
                User user = userService.createUser(managedUserVM.getLogin(), managedUserVM.getPassword(),
                    managedUserVM.getFirstName(), managedUserVM.getLastName(),
                    null, managedUserVM.getImageUrl(),
                    managedUserVM.getLangKey());
                redisTemplate.delete(managedUserVM.getLogin() + type);
                return new ResponseEntity<>(HttpStatus.CREATED);
            });
}
 
@PostMapping(path = "/sendCode", produces = {MediaType.TEXT_PLAIN_VALUE})
@Timed
public ResponseEntity<String> sendCode(@RequestBody MessageDTO messageDTO, @RequestParam(value = "type", required = false) String type) throws ApiException {
    if (redisTemplate.opsForValue().get(messageDTO.getPhone()) != null) {
        if (redisTemplate.opsForValue().get(messageDTO.getPhone()).getTime() != null) {
            long nd = 1000 * 24 * 60 * 60;
            long nh = 1000 * 60 * 60;
            long nm = 1000 * 60;
            long ns = 1000;
            long diff = (redisTemplate.opsForValue().get(messageDTO.getPhone()).getTime().getTime() - new Date().getTime()) % nd % nh % nm / ns;
            if ((int) diff < 60) {
                return new ResponseEntity<>(messageDTO.getPhone() + ":验证码一分钟才能发一次", HttpStatus.METHOD_NOT_ALLOWED);
            }
        }
    }
    if (!sentType.contains(type)) {
        return new ResponseEntity<>("发送类型不匹配", HttpStatus.BAD_REQUEST);
    }
    SendMessageService messageService = new SendMessageService();
    String code = messageService.verificationCode();
   // String statue = messageService.SendMessage(messageDTO, code); // 发送手机验证码
    String statue=null;
    if (statue == null) {// 发送成功
        RegisteredVM registeredVM = new RegisteredVM();
        registeredVM.setCode(code);
        registeredVM.setTime(new Date());
        registeredVM.setSendType(type);
        redisTemplate.opsForValue().set(messageDTO.getPhone() + "," + type, registeredVM);
        redisTemplate.expire(messageDTO.getPhone(), 3, TimeUnit.MINUTES);//设置key存在的时间
        return new ResponseEntity<>(code, HttpStatus.OK);
    } else {
        return new ResponseEntity<>(statue, HttpStatus.BAD_REQUEST);
    }
}



}





 类似资料: