黑马旅游网(番外1):“自动登录”
笔者在之前的一系列博客中将黑马旅游网系列公开视频课程中涉及到的功能进行了分析和实现,详细内容可前往 《黑马旅游网》系列博客及笔者源码传送门 进一步了解和阅读。
1 功能描述
本篇博客将对旅游网站中的用户“自动登陆”功能进行分析和实现。在登陆页面(login.html),可以看到输入表单中有一个复选框,提示内容为 自动登录
。
从使用者的角度看,若用户勾选了 自动登录
,则当用户结束本次浏览并关闭浏览器后,下一次再打开该网站时将不必再跳转至 login.html 页面执行登陆操作。也就是达到了 “自动登录” 的效果。
2 功能分析
在笔者查阅过的书籍和博客中,前端和后端都可以实现 “自动登录” 功能。在本篇博客中,笔者会介绍一种在后端实现 “自动登录” 的方式,如果你有其它的方法,欢迎分享和讨论。
2.1 Session 与 Cookie
实现 “自动登录”,一个绕不开话题就是 Session 与 Cookie。关于 HTTP 协议中的这两个概念,笔者有以下理解:
- Session(会话)是维持浏览器与服务器之间相互沟通的载体,它的实例对象保存在服务器中,以
SessionID
作为唯一性标识。 - Cookie 是记录浏览器与服务器之间相互识别认证以及客户端状态的信息的载体,它的实例对象被保存在浏览器。Cookie 能够保存浏览器与服务器沟通的 Session 对象的
SessionID
。
可以通过一张图来加深对 Session 和 Cookie 的理解:
如何利用 Cookie 实现浏览器与服务器之间的相互验证,个人认为《图解HTTP》一书中的配图理解起来比较直观:
- 没有 Cookie 信息状态下的请求
- 第 2 次以后(存有 Cookie 信息状态) 的请求
在抓包工具中,我们也可以从请求头中发现 Cookie 中携带的SessionID
:
2.2 “自动登陆” 的本质
在黑马旅游网(3):登录与退出中我们详细地分析了登录功能的业务逻辑和代码实现。其中有提及,当用户通过所有的验证条件(验证码、用户名及密码等)后,会将从数据库中提取并封装的 User Bean 对象保存在 Session 对象中。
Session session = request.getSession(); // 获取Session对象
/* 登录信息校验 */
// 6.用户名和密码正确且已激活,跳转网站首页
if (loginUser != null && "Y".equals(loginUser.getStatus())) {
resultInfo.setFlag(true);
session.setAttribute("user", loginUser); // 将User对象添加到Session中
}
由此可知,用户登录就是在 Session 中保存了用户的身份信息。即:在这个 Session 中,用户处于 已登录状态 或者简称为 登录状态。
结合前文中对 “利用 Cookie 实现身份验证” 的图示,一种实现 “自动登录” 功能的思路是:若能够使浏览器能够长时间的保存一份记录用户处于 登陆状态 的 Sesion 的 SessionID
,那么当浏览器再次访问服务器并提交 Cookie 内容时,服务器就能够根据 Cookie 中保存的 SessionID
找到之前的 Session 对象,进而将用户的个人信息响应回浏览器并渲染到前端页面上,也就实现了 “自动登录”。从这个实现思路可以发现:“自动登录” 并不是浏览器自动地将 用户名
和 密码
记住并发送给服务器,而是在用户上一次登录时记住了用户的登陆状态。所谓 “自动登录”,本质上是用户 登陆状态 的持久化。这也是为什么我始终对 “自动登录” 四个字添加引号。
2.3 Cookie 的生命周期与作用域
2.3.1 生命周期
显然,持久化登录状态需要满足两点:
- 在浏览器中持久保存 Cookie
- 在服务器中持久保存 Session
关于 Session 的生命周期与持久化,这又是一个值得深挖的话题。日后可以单独写一篇博客讨论。而对于 Cookie,HTTP 协议中规定服务器可以通过 Set-Cookie
的方式来设置 Cookie 在浏览器中的生命周期。在以 Java 作为编程语言的 Web 开发中,具体的实现方式是:
Cookie cookie = new Cookie(); // 生成Cookie对象
cookie.setMaxAge(60); // 设置Cookie在浏览器中保存60秒
2.3.2 作用域
Cookie 的作用域是另外一个不能忽视的参数。对于本实战项目中的登录业务,我们希望用户的登录状态在该域名下的所有 Servlet 中都能够实现持久化。
Cookie cookie = new Cookie(); // 生成Cookie对象
cookie.setPath("/"); // 设置Cookie在全域名生效
2.4 实现 “自动登陆”
基于以上叙述,我们现在可以清晰地梳理和实现登陆状态持久化的业务逻辑。在登陆页面,前端会提示用户勾选 自动登录
checkbox。checkbox 属于 form 表单中的一个元素。当提交整个表单时,后端在 Servlet 层可以利用 request.getParameterMap() 方法判断是否包含 checkbox 对应的键。若包含则说明用户勾选 自动登录
,执行 Cookie 持久化即可;否则跳过持久化流程。
3 代码实现
3.1 前端
login.html
<!--
form表单中的checkbox元素,
设置input标签中的name属性时,
后端利用 request.getParameterMap()方法即可获得此键名,
表示用户勾选了自动登录
-->
<div class="auto_login">
<label>
<input type="checkbox" name="auto_login" class="checkbox">
</label>
<span>自动登录</span>
</div>
3.2 后端
BaseServlet.java
/**
* 重载方法,向客户端浏览器回传Cookie
* @param cookie Cookie对象
* @param maxAge Cookie生命周期
* @param path Cookie作用域
* @param response Http响应对象
*/
public void writeCookie(Cookie cookie, int maxAge, String path, HttpServletResponse response) {
cookie.setMaxAge(maxAge);
cookie.setPath(path);
response.addCookie(cookie);
}
UserServlet.java
/**
* 用户登陆方法
*/
public void login(HttpServletRequest request, HttpServletResponse response) throws IOException {
/* 用户身份校验 */
// 获取用户提交的表单信息
Map<String, String[]> parameterMap = request.getParameterMap();
// 判断用户是否勾选`自动登陆`
if (parameterMap.containsKey("auto_login")) { // 用户勾选了`自动登录`
// 创建一个Cookie对象,设置`JSESSIONID`属性为当前session对象的id值
Cookie jSessionIdCookie = new Cookie("JSESSIONID", session.getId());
// 将该Cookie对象回写给浏览器,并设置maxAge令浏览器持久化保存用户的登陆状态,设置作用域为"/",即全域生效
this.writeCookie(jSessionIdCookie, 60*60*24*7, "/", response);
}
/* 将登录用户信息响应会浏览器渲染 */
}
4 相关链接
项目课程链接:https://www.bilibili.com/video/BV1CE411E7h4
完整课程连接:https://www.bilibili.com/video/BV1uJ411k7wy
《黑马旅游网》系列博客及笔者源码传送门:https://blog.csdn.net/xing123456jl/article/details/109173068