说明:会话,是指浏览器与服务器的一次连接,会话建立完成后,只有一方断开连接,会话才算结束,一次会话中可以包含多次请求和响应。会话跟踪是一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据。例如,打开电脑,进入B站,点击页面内容,并不需要每点开一个页面都要扫码,核实身份,这就用到了会话跟踪技术。
目前的会话跟踪方案有Cookie、Session和JWT令牌三种。
一、Cookie
Cookie是客户端会话跟踪技术,它是存储在客户端浏览器的。当浏览器第一次给服务器发送请求时(比如登录),服务器会自动为该客户端设置一个Cookie(setCookie),该Cookie中可以存储一些用户信息(如账号、密码),响应时会把Cookie的值自动返回给客户端,之后客户端再次发送请求时,会自动携带服务端为客户端设置的Cookie内容。
后续,客户端携带Cookie再次发送请求,服务端会判断该Cookie是否存在,如果不存在,说明客户端没有登录,返回给客户端登录页面或限制显示内容(未登录的内容),如果存在,说明客户端已登录,返回给客户端已登录的内容。
使用Cookie,优点是HTTP协议支持的技术,浏览器自动设置,不需要手动设置,但除此有以下缺点:
(1)不安全,Cookie存储在客户端浏览器,用户可以禁用Cookie;
(2)不能实现跨域,当服务器端口、协议和IP任意一个发生改变时,Cookie就不能使用;
(3)移动端无法使用;
二、Session
Session是基于Cookie的一种会话跟踪技术,当浏览器客户端第一次访问服务端时,服务端会建立一个会话对象Session,每个Session对象都会有一个ID。当服务端响应数据时,会将Session的ID(JSESSIONID)通过Cookie响应给浏览器,而Session对象存在服务器本地。
之后,在浏览器发生请求时,会携带JSESSIONID,服务器会根据JSESSIONID查找本地的Session,根据查找结果判断客户是否已建立过会话。
因为Session是存储在服务器的,相较于Cookie安全,但依旧有缺点,如下:
(1)因为JSESSIONID是存在服务器本地的,所以在服务器集群环境下,即有多台服务器时,就无法使用Session;
(2)Cookie的缺点,Session也存在;
三、JWT令牌
JWT(JSON Web Token),是将用户的信息通过算法,生成一串字符,作为用户身份表示的技术。具体的应用场景是,我们可以在用户登录时,将用户的用户名、密码生成一个Token,然后在用户后续登录时,或者在用户直接访问后台时,拦截用户请求,检查其Token,就不需要用户再重新登录了,是主流的会话跟踪技术。
使用令牌,首先要添加一个依赖
<!--JWT令牌依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!--jdk9以后需添加此依赖-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
生成令牌
/**
* 生成令牌
*/
public void generateJwt(){
// 登录用户
Map<String, Object> map = new HashMap<>();
map.put("username","Tom");
map.put("password","123456");
// 登录用户的数据转成JWT令牌
String token = Jwts.builder()
// 有效载荷
.setClaims(map)
// 签名算法
.signWith(SignatureAlgorithm.HS256, "token")
// 有效时间(24小时有效)
.setExpiration(new Date(System.currentTimeMillis() + 24 * 3600 * 1000))
// 生成
.compact();
System.out.println(token);
}
这就是Token令牌
JWT的组成如下: (JWT令牌由三个部分组成,三个部分之间使用英文的点来分割)
第一部分:Header(头), 记录令牌类型、签名算法等。 例如:{“alg”:“HS256”,“type”:“JWT”}
第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:{“id”:“1”,“username”:“Tom”}
第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来
需要知道的是,JWT令牌并不是加密技术,而是使用了算法转换
解析令牌
要想正确解析令牌,需要满足以下三个条件:
(1)解析是的key值要与生成时的一样;
(2)令牌没有过期;
(3)令牌内容没有被篡改;
@Test
public void parseJwt(){
Claims claims = Jwts.parser()
// 签名算法
.setSigningKey("token")
// 解析令牌,key值要与生成时使用的一样
.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJwYXNzd29yZCI6IjEyMzQ1NiIsImV4cCI6MTY4NjU3OTA0MywidXNlcm5hbWUiOiJUb20ifQ.e7a_DwT76DPEWPdBVV1qed0SW3fMCWOPpDEfg_vRIr8")
// 获取信息
.getBody();
System.out.println(claims);
值得一提的是,令牌的有效期是作为一个元素存储在Map集合中的,且有效期是时间戳 / 1000,即以秒为单位的Long类型值
(生成令牌:令牌有效期作为元素存入到Map中)
(解析令牌:令牌有效期为以秒为单位的Long类型的时间戳)
总结
三种会话跟踪技术的优缺点如下:
Cookie:
优点:因为是HTTP协议支持的技术,各大浏览器厂商自动设置,不需要手动设置;
缺点:(1)不安全,用户可以禁用;(2)无法跨域;(3)移动端不能使用
Session:
优点:安全,session对象是存在服务端的;
缺点:(1)不能用于集群环境;(2)基于Cookie,拥有Cookie的缺点
JWT:
优点:(1)支持PC端、移动端;(2)解决集群环境下的认证问题;(3)减轻服务器的存储压力(无需在服务器端存储)
缺点:需要自己实现(包括令牌的生成、令牌的传递、令牌的校验)