1、整体流程
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/88513ff2b798c39b1a3c5a3b1752f4f8.png)
2、第一步实现短信发送
if(RegexUtils.isPhoneInvalid(phone)){
return Result.fail("手机号格式错误");
}
String code = RandomUtil.randomNumbers(6);
stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY+phone,code,LOGIN_CODE_TTL, TimeUnit.MINUTES);
log.debug("发送验证码成功:"+code);
return Result.ok();
3、前台输入验证码后 进行登录
String phone = loginForm.getPhone();
if(RegexUtils.isPhoneInvalid(phone)){
return Result.fail("手机号格式错误");
}
String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY+phone);
String code = loginForm.getCode();
if(cacheCode==null){
return Result.fail("验证码已过期");
}else if(!cacheCode.equals(code)){
return Result.fail("验证码错误");
}
User user = query().eq("phone", phone).one();
if (user == null){
user = createUserWithPhone(phone);
}
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 token = UUID.randomUUID().toString(true);
stringRedisTemplate.opsForHash().putAll(LOGIN_USER_KEY+token,userMap);
stringRedisTemplate.expire(LOGIN_USER_KEY+token,LOGIN_USER_TTL,TimeUnit.MINUTES);
return Result.ok(token);
4、配置拦截器
由于部分功能,例如:首页、商品信息等,不需要进行登录,所以访问这些资源时我们无需进行拦截。
但是在登录后,访问的这些不进行拦截的页面,导致我们不能及时的刷新用户的token在Redis 库数据中的有效时长,
造成用户在使用过程中,出现登陆状态超时,需要重新登录的问题。
因此,我们需要再添加一个拦截器,对所有的请求进行拦截,并刷新Redis中用户信息存在的时长。
1、配置拦截器,使拦截器生效
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).addPathPatterns("/**").order(0);
registry.addInterceptor(new LoginInterceptor())
.excludePathPatterns("/user/code",
"/shop/**",
"/shop-type/**",
"/blog/hot",
"/uplocad/**",
"/voucher/**",
"/user/login"
).order(1);
}
}
2、配置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 {
String token = request.getHeader("authorization");
if(StrUtil.isBlank(token)){
return true;
}
String key = RedisConstants.LOGIN_USER_KEY + token;
Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);
if(userMap.isEmpty()){
return true;
}
UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);
UserHolder.saveUser(userDTO);
stringRedisTemplate.expire(key,RedisConstants.LOGIN_USER_TTL, TimeUnit.MINUTES);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserHolder.removeUser();
}
}
3、登陆验证,编写请求拦截器
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if(UserHolder.getUser() == null){
response.setStatus(401);
return false;
}
return true;
}
}