基于Session实现登录流程
发送验证码:
用户在提交手机号后,会校验手机号是否合法,如果不合法,则要求用户重新输入手机号
如果手机号合法,后台此时生成对应的验证码,同时将验证码进行保存,然后再通过短信的方式将验证码发送给用户
短信验证码登录、注册:
用户将验证码和手机号进行输入,后台从session中拿到当前验证码,然后和用户输入的验证码进行校验,如果不一致,则无法通过校验,如果一致,则后台根据手机号查询用户,如果用户不存在,则为用户创建账号信息,保存到数据库,无论是否存在,都会将用户信息保存到session中,方便后续获得当前登录信息
校验登录状态:
用户在请求时候,会从cookie中携带者JsessionId到后台,后台通过JsessionId从session中拿到用户信息,如果没有session信息,则进行拦截,如果有session信息,则将用户信息保存到threadLocal中,并且放行
一、实现发送短信验证码功能
service层编写发送验证码
@Override
public Result sendCode(String phone, HttpSession session) {
// 1.校验手机号
if (RegexUtils.isPhoneInvalid(phone)) {
// 2.不符合,滚
return Result.fail("手机号格式不正确!");
}
// 3.生成验证码
String code = RandomUtil.randomNumbers(6);
// 4.保存验证码到session
session.setAttribute(LOGIN_CODE_KEY,code);
// 5.发送验证码(模拟)
log.debug("发送短信验证码成功,验证码:{}",code);
return Result.ok();
}
这里我学到了两个知识点:
- 使用糊涂工具生成6位随机数:
RandomUtil.randomNumbers(6);
- 记录日志时传递参数:
log.debug("发送短信验证码成功,验证码:{}",code);
二、登录
用户收到验证码后,填写验证码,点击登录后将手机号,验证码发送到后端
@Override
public Result login(LoginFormDTO loginForm, HttpSession session) {
// 1.检查手机号是否正确
if (RegexUtils.isPhoneInvalid(loginForm.getPhone())) {
return Result.fail("手机号格式不正确!");
}
// 2.检查验证码是否一致
Object cacheCode = session.getAttribute(LOGIN_CODE_KEY);
if (cacheCode == null || !cacheCode.toString().equals(loginForm.getCode())){
return Result.fail("验证码错误");
}
// 3.根据手机号查询用户
User user = query().eq("phone", loginForm.getPhone()).one();
// 4.手机号不存在创建用户
if (user == null) {
user = createUserWithPhone(loginForm.getPhone());
}
// 5.将用户存入session中
session.setAttribute("user", BeanUtil.copyProperties(user, UserDTO.class));
return Result.ok();
}
private User createUserWithPhone(String phone) {
User user = new User();
// 设置手机号
user.setPhone(phone);
// 生成随机用户名
user.setNickName("user_" + RandomUtil.randomString(9));
return user;
}
这里利用糊涂工具的BeanUtil工具类进行了类的转换,
BeanUtil.copyProperties(user, UserDTO.class)
将User 类复制到UserDTO 中,有相同的属性则赋值,没有的属性就不赋值,也不会报错进行类的复制是为了让手机号,密码等敏感信息进行隐藏(不返回到前端)
三、配置拦截器
1. 编写拦截器
package com.hmdp.utils;
import com.hmdp.dto.UserDTO;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* @author : 尚腾飞
* @version : 1.0
* @createTime : 2022/10/20 12:46
* @description :
*/
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1.获取session
HttpSession session = request.getSession();
//2.获取session中的用户
Object user = session.getAttribute("user");
//3.判断用户是否存在
if(user == null){
//4.不存在,拦截,返回401状态码
response.setStatus(401);
return false;
}
//5.存在,保存用户信息到Threadlocal
UserHolder.saveUser((UserDTO) user);
//6.放行
return true;
}
}
2. 使拦截器生效
package com.hmdp.config;
import com.hmdp.utils.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author : 尚腾飞
* @version : 1.0
* @createTime : 2022/10/20 12:57
* @description :
*/
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.excludePathPatterns(
"/shop/**",
"/voucher/**",
"/shop-type/**",
"/upload/**",
"/blog/hot",
"/user/code",
"/user/login"
);
}
}
在请求到达的controller返回登录的用户
@GetMapping("/me")
public Result me(){
// 获取当前登录的用户并返回
UserDTO user = UserHolder.getUser();
return Result.ok(user);
}