基于Redis实现session共享的登录验证

                                                 

功能:实现短信验证登录

问题:在多台 Tomcat 服务器的集群环境下,如果没有进行 Session 共享配置,用户在请求被路由到不同的服务器时,Session 数据就会丢失。默认情况下,TomcatSession 是存储在服务器的内存中的,不会在不同的服务器间自动共享。

解决:Redis 是一个内存数据存储,可以用来存储 Session 数据。

特点:符合session的key-value形式

           位于tomcat以外的一种存储形式,任何tomcat都能访问

           内存存储

前台页面

输入手机号,发送验证码请求

 在接口的service中先正则校验手机号的格式-----》通过随机数工具生成六位验证码---》通过redis方法以手机号为Key将验证码存储在redis,并设置一个过期时间。

过期时间:当过期后,Key-Value将从数据库中自动删除

 @Override
    public Result sendCode(String phone, HttpSession session) {
        //校验手机号
        if (RegexUtils.isPhoneInvalid(phone)){
            return  Result.fail("phone err");
        }
        //生成验证码
        String code = RandomUtil.randomNumbers(6);

        //保存到redis
        stringRedisTemplate.opsForValue().set(RedisConstants.LOGIN_CODE_KEY+phone,code,RedisConstants.LOGIN_CODE_TTL, TimeUnit.MINUTES);
        //发送模拟
        log.info(code);

验证码登录和注册

将控制台中返回的验证码输入到输入框,发起登录

依旧校验一下手机号--》通过之前设置的Key从数据库获取保存的验证码,判断是否一样--》根据号码信息从mysql中查询用户信息,判断用户是否存在--》不存在则创建

query().eq("phone", phone).one():MP方法,根据号码返回一条信息

 @Override
    public Result login(LoginFormDTO loginForm, HttpSession session) {
        //校验手机
        String phone = loginForm.getPhone();
        if (RegexUtils.isPhoneInvalid(phone)){
            return  Result.fail("phone err");
        }
        //校验验证码,从redis获取
        String code = stringRedisTemplate.opsForValue().get(RedisConstants.LOGIN_CODE_KEY + phone);
        if (code==null||!code.equals(loginForm.getCode())){
            Result.fail("code err");
        }
        //没问题,查用户
        User user = query().eq("phone", phone).one();
        //不存在则创建
        if (user==null){
            user=createUser(phone);
        }
private User createUser(String phone){
        User user = new User();
        user.setPhone(phone);
        user.setNickName("user_"+RandomUtil.randomString(6));
        save(user);
        return user;
    }

--》将创建的用户存储到redis

由于user有密码,电话等敏感信息,所以只需要存储几个普通信息就行了,准备一个实体类并转换一下

@Data
public class UserDTO {
    private Long id;
    private String nickName;
    private String icon;
}



UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);

 我们需要将这个对象以Hash(键值对的集合)的结构存储到redis。由于stringRedisTemplate处理的是字符串类型,然后id是Long类型的,所以以下会报错:类型转换错误

putAll:一次性将Map中的键值对存入redis

UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
        Map<String, Object> stringObjectMap1 = BeanUtil.beanToMap(userDTO);
        stringRedisTemplate.opsForHash().putAll(stringObjectMap1);

我们就自己手动写一个Map,键值都是String类型的

valueOf: 更加安全,因为它可以处理 null 值。如果对象是 null,它会返回 "null" 字符串,而不是抛出 NullPointerException。toString处理非NULL

存入的Key要随机生成,这样比较安全一些,如果直接写号码,容易轻易被获取保存。

 //生成一个token作为key值,
String token = UUID.randomUUID().toString(true);

 Map<String, String> stringObjectMap = new HashMap<>();
         stringObjectMap.put("id",String.valueOf(userDTO.getId()));
         stringObjectMap.put("nickName",String.valueOf(userDTO.getNickName()));
         stringObjectMap.put("icon",String.valueOf(userDTO.getIcon()));


存入
stringRedisTemplate.opsForHash().putAll("login:token"+token,stringObjectMap);

同样也要给这个token设置有效期,最后返回给前端

 stringRedisTemplate.expire("login:token"+token,30,TimeUnit.MINUTES);

        return Result.ok(token);

 查看

docker容器化mysqlicon-default.png?t=O83Ahttps://mp.csdn.net/mp_blog/creation/editor/142057264

 AOP切面应用icon-default.png?t=O83Ahttps://mp.csdn.net/mp_blog/creation/editor/141781810

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值