《基于 Redis 实现短信登录》文章封面
技术笔记约 7 分钟

基于 Redis 实现短信登录

基于 Redis 完成短信验证码登录、Token 会话保存与双拦截器续期的完整流程。

#Redis#Java#登录认证
文章目录0%
  1. 01一、发送手机验证码功能
  2. 02校验手机号格式
  3. 03调用hutool包生成验证码
  4. 04保存验证码到Redis中
  5. 05二、实现登录功能
  6. 06校验手机号格式
  7. 07从Redis中获取验证码校验
  8. 08通过手机号查询用户
  9. 09存在,将用户信息保存到Redis
  10. 10三、配置拦截器
  11. 11刷新token拦截器
  12. 12含义
  13. 13理由
  14. 14做法
  15. 15登录拦截器

一、发送手机验证码功能

校验手机号格式

//1.校验手机号
        if (RegexUtils.isPhoneInvalid(phone)) {
            //2.不符合返回错误信息
            return Result.fail("手机号格式错误");
        }

调用hutool包生成验证码

String code = RandomUtil.randomNumbers(6);

保存验证码到Redis中

设置key=login:code:手机号,value=code,有效期为两分钟

二、实现登录功能

校验手机号格式

//1.校验手机号
        String phone = loginForm.getPhone();
        if (RegexUtils.isPhoneInvalid(phone)) {
            //2.如果不符合,返回错误信息
            return Result.fail("手机号格式错误");
        }

从Redis中获取验证码校验

String cacheCode = stringRedisTemplate.opsForValue().get(RedisConstants.LOGIN_CODE_KEY + phone);
        String code = loginForm.getCode();
        if (cacheCode == null || !cacheCode.equals(code)) {
            //4.不一致报错
            return Result.fail("验证码错误");
        }

通过手机号查询用户

//5.一致通过手机号查询用户
User user = query().eq("phone", phone).one();
//6.判断用户是否存在
if (user == null) {
    //7.不存在,创建用户并保存
    user = createUserWithPhone(phone);
}

存在,将用户信息保存到Redis

随机生成token,作为登录令牌

String token = UUID.randomUUID().toString(true);

将用户信息转为HashMap

UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),
        CopyOptions.create().setIgnoreNullValue(true)
                .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString())

);

存储

String tokenKey = RedisConstants.LOGIN_USER_KEY + token;
stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);
//8.4设置有效期
stringRedisTemplate.expire(tokenKey, RedisConstants.LOGIN_USER_TTL, TimeUnit.MINUTES);

三、配置拦截器

刷新token拦截器

含义

当用户请求某个接口时,会刷新token的有效期

理由

保存登录状态,优化用户体验

做法

获取请求头的token,判断是否登录
//获取请求头中的token
String token = request.getHeader("authorization");

//是空的,证明没有登录,交由下一个拦截器处理
if (!StrUtil.isNotBlank(token)) {
    return true;
}
通过token获取Redis中的用户
String key = RedisConstants.LOGIN_USER_KEY + token;
Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);
//非空判断
        if (userMap.isEmpty()) {
            return true;
        }
保存到上下文中,后续业务使用
//将查询到hash数据转换为userDto对象
UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);
UserHolder.saveUser(userDTO);
刷新token有效期
stringRedisTemplate.expire(key,RedisConstants.LOGIN_USER_TTL, TimeUnit.MINUTES);

登录拦截器

仅仅做登录拦截即可

if (UserHolder.getUser() == null) {
    response.setStatus(401);
    return false;
}