1.点击发送验证码
1.1校验手机格式 如果错误则返回
1.2生成6位随机数验证码
1.3把验证码保存到redis并设置过期时间 以手机号码作为key 短信号码作为value
1.4发送到控制台
public Result sendCode(String phone, HttpSession session) {
//1,校验手机号
if(RegexUtils.isPhoneInvalid(phone)){
//2,如果不符合,返回错误信息
return Result.fail("手机号格式错误");
}
//3,符合,生成验证码
String code = RandomUtil.randomNumbers(6);
//4.保存验证码到redis 有效期两分钟 set key value ex 120
stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY+phone,code,LOGIN_CODE_TTL, TimeUnit.MINUTES);
//5,发送验证码
log.debug("发送短信验证码成功,验证码:"+code);
//返回ok
return Result.ok();
}
2.登录
2.1校验手机号
2.2从redis获取验证码并校验
2.3如果一致,查询数据库如果不存在就创建然后保存
2.4随机生成token
2.5把user转化为map
2.6把userMap信息存入redis(以token为key) hashset
2.7设置token(key)有效时期
2.8把token返回给浏览器
public Result login(LoginFormDTO loginForm, HttpSession session) {
String phone = loginForm.getPhone();
//1,校验手机号
if(RegexUtils.isPhoneInvalid(phone)){
//2,如果不符合,返回错误信息
return Result.fail("手机号格式错误");
}
//3,从redis获取验证码并校验
String sessionCode =stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY+phone);
String code = loginForm.getCode();
if(sessionCode==null||!sessionCode.equals(code)){
//3,不一致,报错
return Result.fail("验证码错误");
}
//4,一致,根据手机号查询用户 select *from tb_user where phone =?
User user = query().eq("phone", phone).one();
//5,判断用户是否存在
if(user==null){
//6,不存在 创建用户并保存
user=creteUserWithPhone(phone);
}
//TODO 7,存在,保存用户到redis中
//TODO 7.1 随机生成token
String token = UUID.randomUUID().toString();
//TODO 7.2 将User对象转为hash储存
UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
Map<String, Object> map = BeanUtil.beanToMap(userDTO, new HashMap<>(),
CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
//TODO 7.3 储存user到redis
String tokenKey=LOGIN_USER_KEY+token;
stringRedisTemplate.opsForHash().putAll(tokenKey,map);
//设置token有效期
stringRedisTemplate.expire(tokenKey,LOGIN_USER_TTL,TimeUnit.MINUTES);
//TODO 7.4返还token
return Result.ok(token);
}
3.token刷新机制 通过拦截器
3.1通过request拿到token
3.2如果token为空直接返回 进入二层拦截器
3.3通过token拿到redis中的用户。判断用户是否存在 若不存在直接返回进入二层拦截器
3.4把用户转为userDTO对象
3.5保存在ThreadLocal之中
3.6刷新token有效期
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//TODO 1获取请求头中token
String token = request.getHeader("authorization");
if (StrUtil.isBlank(token)){//如果token为空
return true;
}
//TODO 2 基于token获取redis 中的用户
Map<Object, Object> entries = stringRedisTemplate.opsForHash()
.entries(RedisConstants.LOGIN_USER_KEY + token);
//TODO 3 判断用户是否存在
if(entries.isEmpty()){
return true;
}
//TODO 5 将查询到的Hash数据转为UserDto对象
UserDTO userDTO = BeanUtil.fillBeanWithMap(entries, new UserDTO(), false);
//TODO 6 存在保存信息到ThreadLocal
UserHolder.saveUser(userDTO);
// TODO 7.刷新token有效期
stringRedisTemplate.
expire(RedisConstants.LOGIN_USER_KEY + token,RedisConstants.LOGIN_USER_TTL, TimeUnit.MINUTES);
return true;
}
4.二层拦截器
4.1.从ThreadLocal里面拿user如果为null直接返回flase拦截
4.2如果不为null 就返回ture 通行
//二层拦截
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//判断是否需要拦截
if(UserHolder.getUser()==null){
response.setStatus(401);
return false;
}
//有用户就放行
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//移除用户
UserHolder.removeUser();
}
UserHolder代码
public class UserHolder {
private static final ThreadLocal<UserDTO> tl = new ThreadLocal<>();
public static void saveUser(UserDTO userId){
tl.set(userId);
}
public static UserDTO getUser(){
return tl.get();
}
public static void removeUser(){
tl.remove();
}
}