目录
基于Redis实现短信登录
基于Redis实现短信登录
实现流程图
实现代码
@Overridepublic 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()));//存储tokenString 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对象是否存在即可,完成整体刷新功能。
实现代码
发送验证码
@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic Result sendCode(String phone, HttpSession session) {//校验手机号if (RegexUtils.isPhoneInvalid(phone)){//不符合return Result.fail("手机号格式错误");}//符合生成验证码String code = RandomUtil.randomNumbers(6);//保存验证码到redisstringRedisTemplate.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;}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//获取请求头中的tokenString 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值转为userDtoUserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);//保存用户信息到threadLocalUserHolder.saveUser(userDTO);stringRedisTemplate.expire(key,RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);//放行return true;}@Overridepublic 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;}