
基于 Redis 实现短信登录
基于 Redis 完成短信验证码登录、Token 会话保存与双拦截器续期的完整流程。
文章目录
一、发送手机验证码功能
校验手机号格式
//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;
}


