单系统登录机制
http无状态协议
web应用采用browser/server架构,http作为通信协议,HTTP是无状态协议,用户向服务端发起多个请求,服务端并不会知道这多次请求都是来自同一用户,这个就是无状态的。但是我们可以通过手段去处理,比如每次用户发起请求的时候携带一个userid或者user-token,如此一来,就能让服务端根据用户id或token来获得相应的数据。每个用户的下一次请求都能被服务端识别来自同一个用户。
http保持状态的4种方法:
1、隐藏域
将值放在HTML表单的隐藏域中。当用户提交表单时,隐藏域中的值也传送到服务器。只有当页面包含表单,或者可以在页面中添加表单时,才适合使用隐藏域。
2、Cookie 客户端保持状态(在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话)
Cookie是通过客户端保持状态的解决方案。从定义上来说,Cookie就是由服务器发给客户端的特殊信息,而这些信息以文本文件的方式存放在客户端,然后客户端每次向服务器发送请求的时候都会带上这些特殊的信息。
说得更具体一些:当用户使用浏览器访问一个支持Cookie的网站的时候,用户会提供包括用户名在内的个人信息并且提交至服务器;接着,服务器在向客户端回传相应的超文本的同时也会发回这些个人信息,当然这些信息并不是存放在HTTP响应体(Response Body)中的,而是存放于HTTP响应头(Response Header);当客户端浏览器接收到来自服务器的响应之后,浏览器会将这些信息存放在一个统一的位置,自此,客户端再向服务器发送请求的时候,都会把相应的Cookie再次发回至服务器。而这次,Cookie信息则存放在HTTP请求头(**Request Header)了。
有了Cookie这样的技术实现,服务器在接收到来自客户端浏览器的请求之后,就能够通过分析存放于请求头的Cookie得到客户端特有的信息,从而动态生成与该客户端相对应的内容。
3、Session 服务器来保持状态(现代都是这种实现)
与Cookie相对的一个解决方案是Session,它是通过服务器来保持状态的。
我们通常都会把Session翻译成会话,会话Session代表的是客户端与服务器的一次交互过程,这个过程可以是连续也可以是时断时续的。曾经的Servlet时代(jsp),一旦用户与服务端交互,服务器就会在内存中为用户开辟一个存储空间(即创建一个session),并将sessionid作为响应的一部分发送给浏览器,浏览器通过cookie存储sessionid,每次交互都会携带。如此一来,服务器只要在接到用户请求时候,就可以拿到jsessionid,并根据这个id在内存中找到对应的会话session,当拿到session会话后,那么我们就可以操作会话了。会话存活期间,我们就能认为用户一直处于正在使用着网站的状态,一旦session超期就可以认为用户已经离开网站,停止交互了。用户的身份信息,我们也是通过session来判断的,在session中可以保存不同用户的信息。
这个过程用下图说明,后续请求与第一次请求产生了关联。
服务器在内存中保存会话对象,浏览器通过cookie保存sessionid,每次发送http请求时浏览器自动发送会话id,cookie机制正好用来做这件事。
tomcat会话机制当然也实现了cookie,访问tomcat服务器时,浏览器中可以看到一个名为“JSESSIONID”的cookie,这就是tomcat会话机制维护的会话id,使用了cookie的请求响应过程如下图。
4、重写URL
如果浏览器支持Cookie,Servlet容器就把SessionID作为Cookie保存在浏览器中。如果浏览器出于安全的原因,禁用Cookie,不允许服务器像客户端存放Cookie。Servlet容器可以重写Web组件的URL,把Session ID添加到URL信息中。
HttpServletResponse接口提供了重写URL的方法:
public String encodeURL(String url)
public String encodeRedirectURL(String url)
只有在当前Web组件支持Session,并且浏览器不支持Cookie的情况下,encodeURL方法才会重写URL,否则直接返回参数指定的原始URL。
即:原始URL
www.baidu.com
重写URL
www.baidu.com?jsessionid=jkahsduiheyuidhauidh
tomcat判断客户端浏览器是否支持Cookie的依据是请求中是否含有Cookie。尽管客户端可能会支持Cookie,但是由于第一次请求时不会携带任何Cookie(因为并无任何Cookie可以携带),URL地址重写后的地址中仍然会带有jsessionid。当第二次访问时服务器已经在浏览器中写入Cookie了,因此URL地址重写后的地址中就不会带有jsessionid了。
Cookie和Session基础知识
Cookie
其实本质上cookies就是http的一个扩展。有两个http头部是专门负责设置以及发送cookie的,它们分别是Set-Cookie以及Cookie。当服务器返回给客户端一个http响应信息时,其中如果包含Set-Cookie这个头部时,意思就是指示客户端建立一个cookie,并且在后续的http请求中自动发送这个cookie到服务器端,直到这个cookie过期。如果cookie的生存时间是整个会话期间的话,那么浏览器会将cookie保存在内存中,浏览器关闭时就会自动清除这个cookie。另外一种情况就是保存在客户端的硬盘中,浏览器关闭的话,该cookie也不会被清除,下次打开浏览器访问对应网站时,这个cookie就会自动再次发送到服务器端。
一个cookie的设置以及发送过程分为以下四步:
- 客户端发送一个http请求到服务器端
- 服务器端发送一个http响应到客户端,其中包含Set-Cookie头部
- 客户端发送一个http请求到服务器端,其中包含Cookie头部
- 服务器端发送一个http响应到客户端
什么是Cookie?
是由W3C组织提出,最早由Netscape社区发展的一种机制。目前Cookie已经成为标准,所有的主流浏览器如IE、Netscape、Firefox、Opera等都支持Cookie。
Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
在浏览器地址栏输入javascript:alert (document. cookie)(需要有网才能查看),就可以查看当前页面的cookie
Java中把Cookie封装成了javax.servlet.http.Cookie类。每个Cookie都是该Cookie类的对象。服务器通过操作Cookie类对象对客户端Cookie进行操作。通过request.getCookie()获取客户端提交的所有Cookie(以Cookie[]数组形式返回),通过response.addCookie(Cookie cookie)向客户端设置Cookie。Cookie对象使用key-value属性对的形式保存用户状态,一个Cookie对象保存一个属性对,一个request或者response同时使用多个Cookie。
Cookie不可跨域
很多网站都会使用Cookie。如,淘宝会向客户端颁发Cookie,京东也会向客户端颁发Cookie。那浏览器访问淘宝会不会也携带上京东颁发的Cookie呢?当然不能。Cookie在客户端是由浏览器来管理的。浏览器能够保证淘宝只会操作淘宝的Cookie而不会操作京东的Cookie,从而保证用户的隐私安全。浏览器判断一个网站是否能操作另一个网站Cookie的依据是域名。淘宝与京东的域名不一样,因此淘宝不能操作京东的Cookie。
Session
Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。
如果说Cookie机制是通过检查客户身上的“通行证”来确定客户身份的话,那么Session机制就是通过检查服务器上的“客户明细表”来确认客户身份。Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了。
Session对应的类为javax.servlet.http.HttpSession类。每个来访者对应一个Session对象,所有该客户的状态信息都保存在这个Session对象里。Session对象是在客户端第一次请求服务器的时候创建的。Session也是一种key-value的属性对,通过getAttribute(Stringkey)和setAttribute(String key,Objectvalue)方法读写客户状态信息。Servlet里通过request.getSession()方法获取该客户的Session。当多个客户端执行程序时,服务器会保存多个客户端的Session。获取Session的时候也不需要声明获取谁的Session。Session机制决定了当前客户只会获取到自己的Session(通过session id),而不会获取到别人的Session。各客户的Session也彼此独立,互不可见。
Session的生命周期
Session保存在服务器端。为了获得更高的存取速度,服务器一般把Session放在内存里。每个用户都会有一个独立的Session。如果Session内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。因此,Session里的信息应该尽量精简。
Session在用户第一次访问服务器的时候自动创建。需要注意只有访问Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session。Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。用户每访问服务器一次,无论是否读写Session,服务器都认为该用户的Session“活跃(active)”了一次。服务器会把长时间没有活动的Session从服务器内存中清除,此时Session便失效。Tomcat中Session的默认失效时间为20分钟。session的过期时间是从session不活跃(最后一次访问时间)的时候开始计算,一旦Session被访问,计时清0。
后记:
web系统早已从久远的单系统发展成为如今由多系统组成的应用群,面对如此众多的系统,用户难道要一个一个登录、然后一个一个注销吗?
web系统由单系统发展成多系统组成的应用群,复杂性应该由系统内部承担,而不是用户。无论web系统内部多么复杂,对用户而言,都是一个统一的整体,也就是说,用户访问web系统的整个应用群与访问单个系统一样,登录/注销只要一次就够了。
虽然单系统的登录解决方案很完美,但对于多系统应用群已经不再适用了,为什么呢?
单系统登录解决方案的核心是cookie,cookie携带会话id在浏览器与服务器之间维护会话状态。但cookie是有限制的,这个限制就是cookie的域(通常对应网站的域名),浏览器发送http请求时会自动携带与该域匹配的cookie,而不是所有cookie。既然这样,为什么不将web应用群中所有子系统的域名统一在一个顶级域名下,例如“.baidu.com”,然后将它们的cookie域设置为“.baidu.com”,这种做法理论上是可以的,甚至早期很多多系统登录就采用这种同域名共享cookie的方式。然而,可行并不代表好,共享cookie的方式存在众多局限。首先,应用群域名得统一;其次,应用群各系统使用的技术(至少是web服务器)要相同,不然cookie的key值(tomcat为JSESSIONID)不同,无法维持会话,共享cookie的方式是无法实现跨语言技术平台登录的,比如java、php、.net系统之间;第三,cookie本身不安全。
因此,我们需要一种全新的登录方式来实现多系统应用群的登录,这就是单点登录