Cookie + Session登录原理剖析

发布时间 2023-03-29 16:37:53作者: 車轱辘

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的标识,实现登录流程如下:

sequenceDiagram     participant User     participant Server     User->>+Server: Sends login credentials     Server->>+Server: Verifies credentials     alt Session-Based Authentication         Server->>+Server: Creates session         Server-->>-User: Sends session ID in response as cookie     else Cookie-Based Authentication         User-->>+Server: Send request with cookie         Server->>+Server: judge sessionID in cookie         Server-->>-User: retrurn reponse context     end
  • 用户第一请求服务器时,服务器根据用户提交的登录凭证,创建对应的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来存储。