Session与Cookie
HTTP协议本身是无状态的,当用户的第一次请求结束后,后端服务器需要区分前端请求用户的身份,因此需要前端提供身份标识。基于HTTP协议支持会话状态的机制,这个机制可以使Web服务器从多次单独的HTTP请求中知道哪些请求是来自哪个会话的。这个机制则是通过Session与Cookie来实现。
Cookie就是当一个用户通过HTTP协议访问一个服务器的,服务器会将一些Key/Value键值对返回给客户端浏览器,并给这些数据加上一些限制条件,在条件符合时这个用户下次访问这个服务器的时候,数据又被完整地带回给服务器。
Cookie可以让服务端程序跟踪每个客户端的访问,但是每次客户端的访问都必须传回这些Cookie,如果Cookie很多,这无形地增加了客户端与服务端的数据传输量,而Session的出现正是为了解决这个问题。
同一个客户端每次和服务端交互时,不需要每次都传回所有的Cookie值,而是只要传回一个会话标识(SessionId),这个ID是客户端第一次访问服务器的时候生成的,而且每个客户端是唯一的。客户端只要传回这个ID就行了,这个ID通常名为JSESSIONID的一个Cookie。在Web服务器上,各个session会话独立存储保存不同会话的信息。如果遇到禁用Cookie的情况,一般的做法就是把这个会话标识放到URL的参数中。
Cookie和Session都是为了保持用户访问的连续状态。
分布式场景下的问题
当单机的应用服务器变为集群时,就会遇到Session共享的问题。当我们第一次访问网站的时候,负载均衡将本地的请求分配到Web服务器1,那么Session创建在Web服务器1,第二次访问的时候如果我们不做处理就不能保证还是会落到Web服务器1了。因此在不同服务器之间,需要进行session共享。
session共享实现
在分布式场景下,session共享可以考虑放在redis集群中,如何实现在request.getSession或response返回时,将session推送到redis中呢?有框架如spring-session
在servlet中,用servletWrapper在fiter中替换掉原生的request,并往过滤器下游传,servletWrapper中的getSession方法进行重写,即从redis中获取当前会话数据。可以将sessionId做为key,会话数据作为hash结构的数据存储到redis中。
通过将session信息放到分布式缓存redis中时,则实现了服务器是分布式场景下的session数据存储,存在前端是多个不同域名的情况下的session共享,如果多个不同域名存在相同的顶级域名,则可以通过设置顶级域名下的cookie来实现多个域名下的session共享。这样在多个系统在访问后端时,会将cookie带到后台,通过sessionid拿到同一个登录session信息。
如果是跨域情况下的session共享如何实现呢?sso
SSO实现
cas原理,通过页面重定向,把前端身份信息id进行互传。如下,cas.com系统实现登录功能,业务系统通过cas.com进行登录。
1.a.com登录发现未登录
2.跳转cas.com登录成功,此网站有用户登录信息,查询ticket信息,无则登录并存储登录信息
3.跳转回a.com?ticket=xxxx,a系统后台拿到ticket调用cas.com进行校验,通过则表示登录成功。