前言
** 之前在自己的项目中实现了邮箱登录redis存储code,整个设计流程都是自己直觉实现的,总感觉有点不对劲,就准备系统的学习redis,然后看了许多blog和视频之后,发现很多项目的开发流程和我的第一直觉都大同小异hhhhh,但是还是准备系统的记录一下,完善自己的知识框架。这里我先简单记录一下短信登录的实现流程和原理 **
流程
分析在redis中用的什么数据类型?
如果数据量不是很大的话,完全可以使用json存储
但是显然如果用hash结构存储,更容易的对每一个字段处理
key到底存储什么?
这里我们很显然可以直观的使用phone,但是这里更好的方式是存储token,因为token不仅满足redis中key的唯一性,还可以直接解析出其用户的其他信息
这里我们需要注意,使用token代替之后的一些前后端的注意事项:
1.我们需要将token存储在浏览器的内存中,这里可以参考sessionStorage.setItem()方法
2.前端向后端发送需要没有在拦截器中放行的url时,我们需要携带token,我经常采用的是: headers: { Authorization: "Bearer " + token }
这里可以在后端设置
实现短信登录
public Result login(LoginFormDTO loginForm, HttpSession session) {
// 1.校验手机号
String phone = loginForm.getPhone();
if (RegexUtils.isPhoneInvalid(phone)) {
// 2.如果不符合,返回错误信息
return Result.fail("手机号格式错误!");
}
// 3.从redis获取验证码并校验
String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone);
String code = loginForm.getCode();
if (cacheCode == null || !cacheCode.equals(code)) {
// 不一致,报错
return Result.fail("验证码错误");
}
// 4.一致,根据手机号查询用户 select * from tb_user where phone = ?
User user = query().eq("phone", phone).one();
// 5.判断用户是否存在
if (user == null) {
// 6.不存在,创建新用户并保存
user = createUserWithPhone(phone);
}
// 7.保存用户信息到 redis中
// 7.1.随机生成token,作为登录令牌
String token = UUID.randomUUID().toString(true);
// 7.2.将User对象转为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()));
// 7.3.存储
String tokenKey = LOGIN_USER_KEY + token;
stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);
// 7.4.设置token有效期
stringRedisTemplate.expire(tokenKey, LOGIN_USER_TTL, TimeUnit.MINUTES);
// 8.返回token
return Result.ok(token);
}
这里的基本逻辑就是存储token作为key,user转化为hashmap作为value
就是这里的实现是用户30min没有相应,就将token移除
实现流程如下:设置两个拦截器,第一个拦截器用于刷新token,第二个验证是否有资格