实现登录功能:
发送手机验证码:
public Result sendCode(String phone, HttpSession session) {
//获取手机号,校验手机号
//如果不符合,返回错误信息
if (!RegexUtils.isPhoneInvalid(phone)){
//判断手机号是否有效
return Result.fail("请输入正确的手机号");
}
//生成验证码 cn.hutool.core.util.RandomUtil
String code = RandomUtil.randomNumbers(6);
//保存验证码到session中
session.setAttribute("code",code);
//发送验证码
log.debug("发送短信验证码成功:"+code);
return Result.ok();
}
发送短信验证码后登录:
@Override
public Result login(LoginFormDTO loginForm, HttpSession session) {
//登录
//验证手机号是否正确
String phone = loginForm.getPhone();
if (!RegexUtils.isPhoneInvalid(phone)){
//判断手机号是否有效
return Result.fail("请输入正确的手机号");
}
//获取session中的验证码
Object cacheCode = session.getAttribute("code");
String code = loginForm.getCode();
if (cacheCode==null|| !cacheCode.toString().equals(code)){
return Result.fail("验证码错误");
}
//验证码正确,查询当前用户是否存在
User user = query().eq("phone", phone).one();
if (user==null){
//创建新用户
user=createUser(phone);
}
//保存用户信息到session中
session.setAttribute("user",user);
return Result.ok();
}
private User createUser(String phone) {
User user = new User();
user.setPhone(phone);
user.setNickName(USER_NICK_NAME_PREFIX+RandomUtil.randomString(10));
return user;
}
拦截器登录校验:自定义拦截器,添加拦截器
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取cookie中的session
HttpSession session = request.getSession();
Object user = session.getAttribute("user");
//判断session中是否存在user
if(user==null){
//不存在,拦截
response.setStatus(401);
return false;
}
//存在,保存用户信息到ThreadLocal中
UserHolder.saveUser((User) user);
//放行
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserHolder.removeUser();
}
}
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.excludePathPatterns(
"/user/login",
"/user/code",
"/blog/hot",
"/shop/**",
"/shop-type/**",
"/upload/**",
"/voucher/**"
);
}
}
短信验证码:修改session保存验证码为使用redis保存验证码。
登录注册:修改session保存用户信息为使用redis保存用户信息。
@Override
public Result login(LoginFormDTO loginForm, HttpSession session) {
//登录
//验证手机号是否正确
String phone = loginForm.getPhone();
if (!RegexUtils.isPhoneInvalid(phone)){
//判断手机号是否有效
return Result.fail("请输入正确的手机号");
}
//获取session中的验证码
// Object cacheCode = session.getAttribute("code");
//从redish中获取验证码
String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone);
String code = loginForm.getCode();
if (cacheCode==null|| !cacheCode.equals(code)){
return Result.fail("验证码错误");
}
//验证码正确,查询当前用户是否存在
User user = query().eq("phone", phone).one();
if (user==null){
//创建新用户
user=createUser(phone);
}
UserDTO userDTO=new UserDTO();
BeanUtils.copyProperties(user,userDTO);
//保存用户信息到session中
// session.setAttribute("user", userDTO);
//保存用户信息到redis中
//生成token
String token = UUID.randomUUID().toString();
//将userDto转为map
//long类型的id无法存入reids,以下方式将所有的值转为String类型。
Map<String, Object> map = BeanUtil.beanToMap(userDTO,new HashMap<>(),
CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((fildName,filedValue)->
filedValue.toString()
));
//将用户信息存入redis中,给token设置有效期,
stringRedisTemplate.opsForHash().putAll(LOGIN_USER_KEY+token,map);
stringRedisTemplate.expire(LOGIN_USER_KEY+token,LOGIN_USER_TTL,TimeUnit.SECONDS);
//返回token到客户端
return Result.ok(token);
}
拦截器不断刷新token有效期,并且将用户的信息存入ThreadLocal中
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//从请求头中获取token
String token = request.getHeader("authorization");
if(StrUtil.isBlank(token)){
response.setStatus(401);
return false;
}
//根据token查询当前用户,entries
Map<Object, Object> map = stringRedisTemplate.opsForHash().entries(LOGIN_USER_KEY + token);
//判断是否存在
if (map.isEmpty()){
response.setStatus(401);
return false;
}
//将map转为user对象
UserDTO userDTO = BeanUtil.fillBeanWithMap(map, new UserDTO(),false);
//保存用户信息到ThreadLocal中
UserHolder.saveUser(userDTO);
//更新token有效期
stringRedisTemplate.expire(LOGIN_USER_KEY+token,LOGIN_USER_TTL,TimeUnit.SECONDS);
return true;
}
public class RefreshTokenInterceptor implements HandlerInterceptor {
//当前对象没有被spring管理,所以必须自己利用构造函数注入,在配置类中通过依赖注入。
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;
}
//根据token查询当前用户,entries
Map<Object, Object> map = stringRedisTemplate.opsForHash().entries(LOGIN_USER_KEY + token);
//判断是否存在
if (map.isEmpty()){
return true;
}
//将map转为user对象
UserDTO userDTO = BeanUtil.fillBeanWithMap(map, new UserDTO(),false);
//保存用户信息到ThreadLocal中
UserHolder.saveUser(userDTO);
//更新token有效期
stringRedisTemplate.expire(LOGIN_USER_KEY+token,LOGIN_USER_TTL,TimeUnit.SECONDS);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserHolder.removeUser();
}
}
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//判断ThreadLocal中是否存在用户
UserDTO user = UserHolder.getUser();
if (user==null){
response.setStatus(401);
return false;
}
//存在用户,放行
return true;
}
}
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Resource
StringRedisTemplate stringRedisTemplate;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.excludePathPatterns(
"/user/login",
"/user/code",
"/blog/hot",
"/shop/**",
"/shop-type/**",
"/upload/**",
"/voucher/**"
).order(1);
registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).order(0);
}
}