先说一下整个redis 实现共享session 的业务流程:
- ·在发送验证码的时候将手机号和对应验证码以key value 形式存储到redis中
- ·在对比验证码是否一致时,需要从redis里面取出手机号对应的code
- ·会使用UUID 创建一个登录令牌token
- ·将User对象转为 HashMap,并与token令牌一起以hash 键值对形式存储
- ·设置一个token的有效期并返回给前端
- 设置一个新的拦截器,用于刷新token,由于LoginInterceptor没有交给Spring进行管理,因此 StringRedis Template 不能通过@Resource自动注入。需要在配置文件中进行构造器注入。
public Result sendCode(String phone,HttpSession session) {
//校验手机号
//如果不符合就返回错误信息
if RegexUtils.isPhoneInvalid(phone)) {
return Result.failC"手机号格式错误");
}
//符合就发送验证码//胡图工具类的使用
String code = RandomUtil.randomNumbers(6);
//保存验证码到redis设置一个验证码有效时长key-手机号value-验证码stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY
+phone, code, LOGIN_CODE_TTL,TimeUnit.MINUTES);
//发送验证码,返回ok(这里假装发一下验证码,实际上要不调用云平台的服务log.debug("短信验证码为:"+ code);
return Result.ok();
}
public Result login(LoginFormDTO loginForm, HttpSession session) {
//校验⼿机号
String phone = loginForm.getPhone();
if (RegexUtils.isPhoneInvalid(phone)) {
return Result.fail("⼿机号格式错误");
}
//从redis⾥获取并校验验证码
String cashCode =
stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone);//找到key对
应的value
String code = loginForm.getCode();
if (cashCode == null || !cashCode.equals(code)) {
return Result.fail("验证码错误");
}
User user = query().eq("phone", phone).one();//⽤mybatis-plus的框
架查询
if (user == null) {//⽤户不存在就创建出来
user = createUserWithPhone(phone);
}
//保存在redis中
//随机⽣成⼀个token作为登录的令牌
String token= UUID.randomUUID().toString(true);
//将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()));
String tokenKey=LOGIN_USER_KEY+token;
//⽤哈希结构存储 多个字段有多个属性 可以存好⼏个键值对
stringRedisTemplate.opsForHash().putAll(tokenKey,userMap);
//设置token的有效期
stringRedisTemplate.expire(tokenKey,LOGIN_USER_TTL,TimeUnit.MINUTES);//30分钟
//返回token
return Result.ok(token);
}
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 {
// 1.获取请求头中的token
String token = request.getHeader("authorization");
if (StrUtil.isBlank(token)) {
return true;
}
// 2.基于TOKEN获取redis中的⽤户
String key = LOGIN_USER_KEY + token;
Map<Object, Object> userMap =
stringRedisTemplate.opsForHash().entries(key);
// 3.判断⽤户是否存在
if (userMap.isEmpty()) {
return true;
}
// 5.将查询到的hash数据转为UserDTO
UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);
// 6.存在,保存⽤户信息到 ThreadLocal
UserHolder.saveUser(userDTO);
// 7.刷新token有效期
stringRedisTemplate.expire(key, LOGIN_USER_TTL,TimeUnit.MINUTES);
// 8.放⾏
return true;
}