LoginController主要还是提供用户注册和登录的接口,并存储用户持续登录的信息。我们采用session来实现用户的保持登录状态
Session介绍
Session(会话)是服务器和客户端之间的一段互动时间,用于记录用户的状态和活动。在HTTP协议中,Session是一种解决无状态性问题的方法。每次HTTP请求都是独立的,但通过Session,可以将多个请求关联起来,形成连续的用户体验。
Session的工作原理
- 创建Session:当用户第一次访问服务器时,服务器会创建一个唯一的Session ID,并将其发送给客户端。这个Session ID通常存储在客户端的cookie中。
- 维护Session:每次用户请求时,客户端会将Session ID发送回服务器,服务器根据这个ID查找并维护用户的状态信息。
- 销毁Session:当用户注销或Session超时时,服务器会销毁Session,释放资源
Session与Token的区别
在平常后端开发过程中,Token也是一种常用的登录验证方式。但总体而言,Token更适合现代Web应用
- 存储位置:Session数据存储在服务器端,Token数据存储在客户端。
- 安全性:Session相对安全,因为数据保存在服务器端,而Token安全性取决于Token的存储和传输方式,需要设置合理的期限
-
状态管理:Session有状态,服务器需要维护每个用户的会话数据,而Token无状态,所有必要的信息都包含在Token中,服务器不维护会话数据。
基类介绍
LoginController继承自BaseController,BaseController的实现了基本的增删查改功能,并利用session记录用户登录信息
@ModelAttribute
public void setReqAndRes(HttpServletRequest request, HttpServletResponse response) {
this.request = request;
this.response = response;
this.session = request.getSession(true);
loginUser = (User) session.getAttribute("loginUser");
session.setAttribute("kindList", illnessKindService.findList());
}
该函数在每个子类函数执行之前调用,在http请求里面截获logingUser字段,根据这个字段来判断发出该请求的用户
1、注册接口register
注册接口的实现代码如下
@PostMapping("/register")
public RespResult register(User user, String code) {
String email = user.getUserEmail();
if (Assert.isEmpty(email)) {
return RespResult.fail("邮箱不能为空");
}
Map<String, Object> codeData = (Map<String, Object>) session.getAttribute("EMAIL_CODE" + email);
if (codeData == null) {
return RespResult.fail("尚未发送验证码");
}
String sentCode = (String) codeData.get("code");
Calendar calendar = Calendar.getInstance();
calendar.setTime((Date) codeData.get("time"));
calendar.add(Calendar.MINUTE, 5);
if (System.currentTimeMillis() > calendar.getTime().getTime()) {
session.removeAttribute("EMAIL_CODE" + email);
return RespResult.fail("验证码已经超时");
}
if (!sentCode.equals(code)) {
return RespResult.fail("验证码错误");
}
List<User> query = userService.query(User.builder().userAccount(user.getUserAccount()).build());
if (Assert.notEmpty(query)) {
return RespResult.fail("账户已被注册");
}
user.setRoleStatus(0);
user = userService.save(user);
session.setAttribute("loginUser", user);
return RespResult.success("注册成功", user);
}
该注册接口提供了邮箱合法性判断、邮箱验证功能,并默认设置用户权限代码为0,也就是普通用户。邮箱验证的时限为5分钟,超过期限后会从session中移除验证码属性。
注册成功之后,保存user的id到session中
2、登录接口login
登录接口代码如下,总体思路和注册差不多,就是去验证仍然是登录成功后存储用户id到session,存目前加密功能仍在开发中,数据库中存储的密码为明文。
@PostMapping("/login")
public RespResult login(User user) {
List<User> users = userService.query(user);
if (Assert.notEmpty(users)) {
session.setAttribute("loginUser", users.get(0));
return RespResult.success("登录成功");
}
if (Assert.isEmpty(userService.query(User.builder().userAccount(user.getUserAccount()).build()))) {
return RespResult.fail("账户尚未注册");
}
return RespResult.fail("密码错误");
}
3、邮箱验证码发送接口sendEmailCode
访问该接口时,会给指定电子邮箱发送验证码
@PostMapping("/sendEmailCode")
public RespResult sendEmailCode(String email, Map<String, Object> map) {
if (StrUtil.isEmpty(email)) {
return RespResult.fail("邮箱不可为空");
}
// 发送验证码
String verifyCode = emailClient.sendEmailCode(email);
map.put("email", email);
map.put("code", verifyCode);
map.put("time", new Date());
session.setAttribute("EMAIL_CODE" + email, map);
return RespResult.success("发送成功");
}
4、登出
登出需要在session处注销
@GetMapping("/logout")
public String logout() {
session.invalidate();
return "redirect:/index.html";
}
邮箱服务的整体实现我会在下一篇文章中说明