登录认证(3):会话跟踪技术:Session

41 阅读5分钟

Session概览

上文提到了,为了在同一个会话中共享数据(比如用户的登录状态),我们需要使用会话跟踪技术Cookie客户端的会话跟踪技术,是存储在本地浏览器中的。而本文介绍另外一种会话跟踪技术Session,是基于Cookie实现的技术,是存储在服务端的服务端的会话跟踪技术

使用Session

获取Session

如果需要基于Session进行会话跟踪,那么需要在浏览器第一次请求服务器时,在服务端创建一个会话对象Session,而每一个Session会话对象,都有一个独一无二的ID,如图所示:Session括号中的1就表示该Session的id,称为Session的id

image.png

响应Cookie(JSession)

在服务端成功创建一个Session之后,在给浏览器响应数据的时候,会通过CookieSession的ID 响应给浏览器。其原理也是通过响应头:Set-Cookie完成的。上文提到,Set-Cookie响应头是用来响应Cookie的,也可以用于响应Session,这是因为Cookie的名字是固定的,通过JSESSIONID代表Session的ID,当浏览器看到响应头中的Cookie名是JSESSIONID时,就能自动将其识别为Session并将这个Cookie存储在本地浏览器,其原理如图所示:

image.png

查找Session

Cookie存储在本地浏览器之后,后续的每一次请求,都会将Cookie中的数据获取出来,通过请求头Cookie将其携带到服务端,服务端成功获取到JSESSIONID这个cookie的值,也就是Session的独一无二的id值之后,就会从 服务端中的众多Session中进行比对,寻找到当前请求对应的Session ,这样我们就可以通过Session会话对象在同一次会话中的多次请求之间共享数据了,这就是基于Session进行会话跟踪的流程。

image.png

从中不难看出:在大部分情况下Session的底层是基于Cookie实现的,二者的使用逻辑、工作原理几乎是相同的。但是Cookie是存放在本地浏览器的;而Session是存放在服务器端的。

Session测试代码

在服务端创建Session响应前端

/**
 * 创建Session
 * @param session 在服务端创建Session对象
 * @return Result<Void>
 */
@GetMapping("/s1")
public Result<Void> setSession(HttpSession session) {
    log.info("set-HttpSession: {}", session.hashCode());
    // 在session中存储数据
    session.setAttribute("login_user", "tom");
    return Result.success();
}

我们可以直接操作HttpSession对象封装响应给客户端Session数据,通过其自带的setAttribute方法可以便捷封装数据,此时访问/s1查看:

image.png

可以看见,服务端成功响应一个名为JSESSIONCookie以后的每一次请求,都会携带这个Cookie ,服务端会根据JSESSIONID,去寻找对应的Session

在服务端查找对应Session

/**
 * 获取Session中数据
 * @param request 请求数据封装的对象
 * @return Result<Void>
 */
@GetMapping("/s2")
public Result<Object> getSession(HttpServletRequest request) {
    HttpSession session = request.getSession();
    log.info("get-HttpSession: {}", session.hashCode());

    Object loginUser = session.getAttribute("login_user");
    log.info("login_user: {}", loginUser);
    return Result.success(loginUser);
}

服务端中可以直接操作HttpServletRequest对象,获取这次请求中所携带的Session,并使用getAttribute方法便捷的获取Session中的数据,服务端查找对应的Session是根据Session的唯一标识ID查找到的。此时访问/s2查看:

image.png

对比响应请求中的两个CookieJSESSIONID可以发现,是使用的同一个Session,查看控制台日志 发现,服务端成功查找到对应的Session成功获取到对应的数据

image.png

这说明通过Session进行同一次会话中的多次请求共享数据是理论可行的,但真的可行吗?

Session实际不可行

不适应集群环境

现在的大部分项目部署,为了避免单点故障,都不会只部署在一台服务器上,而是通过集群的形式进行部署,一个项目会部署在多台服务器上,每一台部署的内容是一样的。通过负载均衡服务器对用户的请求进行调度,将请求按照服务器的负载,尽量均匀的分配到每一台服务器上:

image.png

假如说通过Session技术进行会话跟踪,那么就有可能出现这样的情况:假如第一次用户登录请求,负载均衡服务器分配到了服务器1,用户完成了登录,在服务器1存储了一个Session,并将其响应给客户端,以便于每一次请求都携带Cookie;用户登录之后开始发送其他请求,此时请求被负载均衡服务器分配到了服务器2,但Session是在服务器1的,服务器2无法识别请求头中的Cookie,所以说判断用户未登录,然后用户又必须登录一次。假如服务器集群十分大,这样的情况就更是频繁。

底层基于Cookie实现

同时,由于在大部分情况下Session的底层是基于Cookie实现的,所以说Cookie的局限,Session都是有的。 所以说在实际开发中,Session使用十分局限。

总结

在大部分情况下,Session的底层是基于Cookie实现的,是在存储在服务端的会话跟踪技术,但由于不适应服务器集群有Cookie的缺点等局限性,所以使用得并不多。总而言之,不论是Cookie还是Session,在实际开发中的使用都比较少,现在大多是通过令牌技术来实现会话跟踪的,且听下回分解。