目录
基于Redis实现短信登录
实现流程图
实现代码
@Override
public Result login(LoginFormDTO loginForm, HttpSession session) {
//校验手机号
String phone = loginForm.getPhone();
if (RegexUtils.isPhoneInvalid(phone)){
//手机号格式错误
return Result.fail("手机号格式错误");
}
//从redis获取验证码并校验
Object cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone);
String code = loginForm.getCode();
if (cacheCode == null){
return Result.fail("请输入验证码");
}
if (!cacheCode.equals(code)){
return Result.fail("验证码错误");
}
//验证码校验成功
User user = query().eq("phone", phone).one();
//判断用户是否存在
if (user == null){
user = createUserWithPhone(phone);
}
//保存用户信息到redis中
String token = UUID.randomUUID().toString(true);
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()));
//存储token
String tokenKey = RedisConstants.LOGIN_USER_KEY + token;
stringRedisTemplate.opsForHash().putAll(tokenKey,userMap);
//设置token有效期
stringRedisTemplate.expire(tokenKey,RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);
return Result.ok(token);
}
解决登录状态刷新问题
初始方案思路:
添加一个新的拦截器,在第一个拦截器中拦截所有的路径,把第二个拦截器做的事情放入到第一个拦截器中,同时刷新令牌,因为第一个拦截器有了threadLocal的数据,所以此时第二个拦截器只需要判断拦截器中的user对象是否存在即可,完成整体刷新功能。
实现代码
发送验证码
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
public Result sendCode(String phone, HttpSession session) {
//校验手机号
if (RegexUtils.isPhoneInvalid(phone)){
//不符合
return Result.fail("手机号格式错误");
}
//符合生成验证码
String code = RandomUtil.randomNumbers(6);
//保存验证码到redis
stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY + phone,code);
//发送验证码
log.debug("验证码下发成功,验证码为:{}",code);
return Result.ok();
}
登陆实现
@Slf4j
public class RefreshTokenInterceptor implements HandlerInterceptor {
private StringRedisTemplate stringRedisTemplate;
public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取请求头中的token
String token = request.getHeader("authorization");
if (StrUtil.isBlank(token)) {
return true;
}
String key = RedisConstants.LOGIN_USER_KEY + token;
//获取session中的用户
Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);
System.out.println(userMap);
//判断用户是否存在
if (userMap.isEmpty()){
return true;
}
//将查询到的hash值转为userDto
UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);
//保存用户信息到threadLocal
UserHolder.saveUser(userDTO);
stringRedisTemplate.expire(key,RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);
//放行
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//销毁用户信息
UserHolder.removeUser();
}
}
如果是新用户则自动创建
private User createUserWithPhone(String phone) {
//创建用户
User user = new User();
user.setPhone(phone);
user.setNickName(USER_NICK_NAME_PREFIX +RandomUtil.randomString(10));
//保存用户
save(user);
return user;
}