Cookie + Session登录原理剖析
Cookie + Session登录
Cookie和Seesion概述
HTTP(超文本传输协议)是一种用于分布式、协作式和超媒体信息系统的应用层协议。它也是一种无状态协议,这里的状态,指的就是在HTTP协议中,服务端不会保存客户端的任何信息。
比如,当浏览器发送请求给服务器,服务器响应了;如果同个浏览器器再次发送请求,它还是会响应。但是,服务器不知道你的就是刚才访问过的那个浏览器。
因此,想要实现业务系统的登录功能,就必须让服务器具备识别浏览器状态的能力。要让服务器记住浏览器请求状态,就有了Cookie和Session机制。
Cookie是保存在客户端的一小块文本串数据。客户端向服务器发送请求时,服务端会向服务端发送一个Cookie,客户端就把Cookie保存起来。在客户端下一次向同一服务器再发起请求时,Cookie被携带发送到服务器。服务端可以根据这个Cookie判断用户的身份和状态。
Session指的是服务端和客户端一次会话的过程。它是一种记录客户状态的机制。不同的是Cookie保存再客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务端把客户端信息以某种形式记录在服务器上。客户端再次访问时只需要从该Session中查找用户的状态。
Cookie和Session的区别
- 存储位置不同,Cookie保存在客户端,Session保存在服务端;
- 存储数据类型不同,Cookie只能保存ASCII码,Session可以存任意类型数据,一般情况我们可以在Session中保持一些常用变量信息,例如UserID等;
- 有效期不同,Cookie可设置长时间保持,比如我们经常使用默认登录功能,Session一般有效时间比较短,客户端关闭或者Session超时都会失效;
- 隐私策略不同,Cookie存储在客户端,比较容易遭到不法获取,Session存储在服务端,安全性相对Cookie要好一些;
- 存储大小不同,单个Cookie保存的数据不能超过4K,Session可能存储数据远高于Cookie。
Cookie和Session实现登录的原理
一般通过使用Cookie记录Session的标识,实现登录流程如下:
- 用户第一请求服务器时,服务器根据用户提交的登录凭证,创建对应的Session,请求返回时,将此Session的唯一标识信息SessionID返回给浏览器,浏览器接收到服务器返回的SessionID信息后,会将此信息存入Cookie中,同时Cookie记录此SessionID是属于哪个域名。
- 当用户第二次访问服务器时,请求会自动判断此域名下是否存在Cookie信息,如果存在,则将自动将Cookie信息也发送给服务端,服务端会从Cookie中获取SessionID,再根据SessionID查找对应的Session信息,如果没有找到,说明用户没有登录或者登录失效,如果找到Session,证明用户已经登录可执行后面操作。
Cookie和Session实现登录的代码逻辑
- LoginServlet.java
// LoginServlet.java
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 登录验证
if (verifyUser(username, password)) {
// 验证成功,创建Session
HttpSession session = request.getSession();
session.setAttribute("username", username);
// 创建Cookie,存储Session ID
Cookie cookie = new Cookie("JSESSIONID", session.getId());
cookie.setMaxAge(30 * 60); // 设置Cookie的过期时间为30分钟
response.addCookie(cookie);
// 登录成功,重定向到首页
response.sendRedirect("index.jsp");
} else {
// 验证失败,返回错误信息
request.setAttribute("error", "用户名或密码错误");
RequestDispatcher rd = request.getRequestDispatcher("login.jsp");
rd.forward(request, response);
}
}
private boolean verifyUser(String username, String password) {
// 验证用户凭据的逻辑
// ...
}
}
- HemoServlet.java
// HomeServlet.java
@WebServlet("/home")
public class HomeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取请求附带的所有Cookie:
Cookie[] cookies = req.getCookies();
// 如果获取到Cookie:
if (cookies != null) {
// 循环每个Cookie:
for (Cookie cookie : cookies) {
// 如果Cookie名称为lang:
if (cookie.getName().equals(session.getId())) {
// 显示主页
request.getRequestDispatcher("home.jsp").forward(request, response);
return;
}
}
}
// 重定向到登录页
response.sendRedirect("login.jsp");
}
}
Cookie和Session实现登录的一些延申问题
分布式环境下Session如何处理?
分布式环境下,客户端请求经过负载均衡,可能分配到不同的服务器上,加入一个用户的请求两次秒有落到同一台服务器上,那么在新的服务器上就没有用户状态的Session。
这个时候,可以使用Redis等分布式缓存来存储Session,在多台服务器之间共享。
客户端无法使用Cookie怎么办?
也可能存在客户端无法使用Cookie的情况,比如浏览器禁用Cookie,或者客户端是安卓,IOS等。
这个时候,可以使用客户端的本地存储,比如浏览器的sessionStorage来存储。