Http协议无状态的特点导致程序无法区分多次请求是否是同一个用户发起,所以,我们就用token、session和cookie的技术来解决无状态的问题

1、Token

Token顾名思义就是令牌、凭证、钥匙,只有这把钥匙,你才能打开门。Token一般都是服务端生成,比如一个web系统,用户登录的时候,服务端校验用户名密码通过以后,会生成一个token,同时会生成refreshToken和一个过期时间,然后将refreshToken和token返回给客户端,客户端会将token保存下来,后续所有的请求都会携带这个token。服务端会判断当前token是否存在已经是否过期。如果token不存在或者过期就会拒绝本次请求。如果token过期怎么办?就用refreshToken刷新时间,当然这里可能还有别的方案。比如只生成token,每次请求的时候都刷新过期时间。如果长时间没有刷新过期时间,那token就会过期。

2、Cookie

image.png
cookie是浏览器的一种策略。
sessionid就是存储在cookie中的。我们知道http协议是无状态的,cookie就是用来解决这个问题的。cookie中可以用来保存服务端返回的一些用户信息的(set-cookie),例如的token、sessionid。每一次的请求,都会携带这些cookie。服务端从请求头中取到cookie中的信息,就可以识别本次请求的来源,这样,http是就是有状态的了。

注意事项

  • cookie存放在客户端,所以是不安全的,人为可以清除。
  • cookie有过期时间设定。

会话cookie: 如果不设置过期时间,说明这个cookie就是当前浏览器的会话时间,浏览器关了,cookie就不存在了。
持久化cookie: 如果有过期时间,cookie就会存储到硬盘上,浏览器关闭不影响cookie。下次打开浏览器,cookie还存在,设置过期时间小于等于0就是删除cookie

  • cookie有大小的限制,4KB。
  • cookiePath 只能作用于当前目录和子目录,否则需要设置cookie作用范围

    用途

    自动登录
    浏览历史,点击历史

Springboot使用Cookie: https://blog.csdn.net/qq_35387940/article/details/83501886

3、Session

image.png
session就是会话,这是服务端的一种操作。当你第一次访问一个web网站的时候,服务端会生成一个session,并有一个sessionid和他对应。这个session是存储到内存中的,你可以向这个session中写入信息,比如当前登录用户的信息。sessionid会被返回到客户端,客户端一般采用cookie来保存。当然这个cookie不用人为写入。用tomcat容器来举个例子。当后端调用HttpServletRequest对象的getSession的方法的时候,tomcat内部会生成一个jsessonid(tomcat sessionid的叫法)。这个jsessonid会随本次请求返回给客户端。

响应头信息
HTTP/1.1 200 OK
Set-Cookie: JSESSIONID=xxxxxxxxxxxxxxxxxxx

这个jessionid就会写到cookie中。之后jessionid就会通过cookie传递到服务端。
这里我们就会很清楚了,session的数据是存储到内存中,那问题就来了,如果我们的服务是分布式部署,有多台机器的话,可能我们第一次登陆的时候,我们把用户的信息存储到了session,但是后面的请求到了B机器上,那B机器是获取不到用户的session的。另外就是session存储在内存中,那服务器重启,session就丢失了,这就是它的弊端。现在有一些技术,例如session共享、iphash、session持久等也可以解决上述问题

spring-session

Spring Session 是 Spring 的项目之一。Spring Session 提供了一套创建和管理 Servlet HttpSession 的方案,默认采用外置的 Redis 来存储 Session 数据,以此来解决 Session 共享的 问题。https://blog.csdn.net/qq_43371556/article/details/100862785

当你第一次访问一个网站的时候,网站服务器会在响应头内加上Set-Cookie:PHPSESSID=nj1tvkclp3jh83olcn3191sjq3(php服务器),或Set-Cookie JSESSIONID=nj1tvkclp3jh83olcn3191sjq3(java服务器)信息,此信息是服务器随机生成的,放在服务器内存里,为了标识唯一的客户端用户,内容不会重复,这就是sessionid.
当浏览器得到这个sessionid会将它放在自己的进程内存里,这里不同的浏览器会有所不同,IE进程间不能共享这个sessionid,也就是新开一个IE将不能共享这个sessionid;而Firefox进程间可以共享.然后你继续发请求给这个网站的时候,浏览器就会把这个sessionid放在请求头里发送给该服务器了,这样服务器得到sessionid后再和自己内存里存放的sessionid对比锁定客户端,从而区分不同客户端,完成会话.
可以看出如果用这种方式,当用户在会话的过程中关闭浏览器结束进程,则这个sessionid将消失,如果用户又打开浏览器想继续这次会话的时候,就会因为发送的请求中没有这个sessionid而使服务器无法辨别该把那个session信息给他,注意(这个时候服务器端的sessionid和sessionid所指向的session都还存在,只是没有正确的sessionid和它匹配而占用服务器内存,只有session过期或服务器重启才释放内存).
上面这种方式叫会话cookie,把cookie放在浏览器内存里,只能在这个浏览器的内存范围里完成会话,是一种不长久的方式,为了能长久会话,就出现了持久化cookie,把cookie固化在用户的计算机上,现在的cookie不单单能存放sessionid,还能放用户信息,样式表信息等.
如果用户禁止了所有cookie的使用,那么会话cookie和持久化cookie都不能用了,有个方案也可以解决问题,就是URL重写,这里要说下的就是URL重写只能实现会话cookie的效果,持久会话实现不了.

End

最后,对于一个分布式的web系统,通用的解决方案就是cookie+token。由服务端生成token,将用户信息与token进行关联,token返回给浏览器,存储到cookie中。后续请求都携带cooke或者将token从cookie取出以参数传递。