Session Cookie Token SSO单点登录

背景

Session这个单词在不同的语境下可以有不同的含义。

  1. 它可以理解为一个抽象概念,即会话,会话用于记录一个用户在我们网站上的一些行为、一些状态,可以理解为一个上下文,Context。这些用户状态可以利用Cookie直接保存在前端; 也可以保存在后台,然后利用Cookie中的Session ID来标识。

  2. 在另外的一些语境下,Session又可以指在后台保存用户状态来实现会话的方式,它把用户状态存储在后台的内存、数据库等介质中,然后我们利用请求的Cookie中保存的Session ID来为这个请求找到它对应的会话。

会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。这里的Session是语境1的意思。

常用的会话跟踪技术是Cookie与Session(语境2)。Cookie通过在客户端记录信息确定用户身份Session通过在服务器端记录信息确定用户身份。后文中的session都是语境2的意思。

在程序中,会话跟踪是很重要的事情。理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。例如,用户A在超市购买的任何商品都应该放在A的购物车内,不论是用户A什么时间购买的,这都是属于同一个会话的,不能放入用户B或用户C的购物车内,这不属于同一个会话。

而Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。即用户A购买了一件商品放入购物车内,当再次购买商品时服务器已经无法判断该购买行为是属于用户A的会话还是用户B的会话了。要跟踪该会话,必须引入一种机制。

Cookie

Cookie就是这样的一种机制。它可以弥补HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话。

Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。由于cookie是存在客户端上的,所以浏览器加入了一些限制确保cookie不会被恶意使用,同时不会占据太多磁盘空间,所以每个域的cookie数量是有限的。

注意:Cookie功能需要浏览器的支持。如果浏览器不支持Cookie或者把Cookie禁用了,Cookie功能就会失效。不同的浏览器采用不同的方式保存Cookie。IE浏览器会在“C:\Documents and Settings\你的用户名\Cookies”文件夹下以文本文件形式保存,一个文本文件保存一个Cookie。

Cookie具有不可跨域名性。Cookie在客户端是由浏览器来管理的。浏览器能够保证Google只会操作Google的Cookie而不会操作Baidu的Cookie,从而保证用户的隐私安全。浏览器判断一个网站是否能操作另一个网站Cookie的依据是域名。Google与Baidu的域名不一样,因此Google不能操作Baidu的Cookie。

正常情况下,同一个一级域名下的两个二级域名如www.aaa.comimages.aaa.com也不能交互使用Cookie,因为二者的域名并不严格相同。如果想所有aaa.com名下的二级域名都可以使用该Cookie,需要设置Cookie的domain参数

eg: 使用Cookie保持登录

如果用户是在自己家的电脑上上网,登录时就可以记住他的登录信息,下次访问时不需要再次登录,直接访问即可。实现方法是把登录信息如账号、密码等保存在Cookie中,并控制Cookie的有效期,下次访问时再验证Cookie中的登录信息即可。

保存登录信息有多种方案。最直接的是把用户名与密码都保持到Cookie中,下次访问时检查Cookie中的用户名与密码,与数据库比较。这是一种比较危险的选择,一般不把密码等重要信息保存到Cookie中

还有一种方案是把密码加密后保存到Cookie中,下次访问时解密并与数据库比较。这种方案略微安全一些。如果不希望保存密码,还可以把登录的时间戳保存到Cookie与数据库中,到时只验证用户名与登录时间戳就可以了。

Cookie的缺点:把所有信息都放在Cookie中,数据容易泄漏,不安全。

Session

Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。

客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。

每个用户访问服务器都会建立一个session。用户与服务器建立连接的同时,服务器会自动为其分配一个SessionId。当用户再次向服务器发起HTTP请求的时候,把这个字符串带上,服务器就可以区分谁是谁。服务器使用session把用户的信息临时保存在了服务器上,用户离开网站后session会被销毁。这种用户信息存储方式相对cookie来说更安全。

Session的缺点:存在服务器负载均衡的问题,严重限制了服务器扩展能力。

比如说我用两个机器组成了一个集群, 小F通过机器A登录了系统,  那session id会保存在机器A上,  假设小F的下一次请求被转发到机器B怎么办?  机器B可没有小F的 session id啊。有时候会采用一点小伎俩: session sticky , 就是让小F的请求一直粘连在机器A上, 但是这也不管用, 要是机器A挂掉了, 还得转到机器B去。那只好做session 的复制了, 把session id  在两个机器之间搬来搬去。

后来有个叫Memcached的支了招: 把session id 集中存储到一个地方, 所有的机器都来访问这个地方的数据, 这样一来,就不用复制了, 但是增加了单点失败的可能性, 要是那个负责session 的机器挂了,  所有人都得重新登录一遍, 估计得被人骂死。

Session 和 Cookie 的关系

  1. 可以完全通过Cookie来实现会话跟踪,即将所有信息存在Cookie中。

  2. 可以完成通过Session来实现会话跟踪,即将SessionId拼接在URL参数中。

  3. Cookie+Session,SessionId通过Cookie存储在浏览器中,当下次请求的时候,浏览器会自动带上SessionId的Cookie。

第一种情况,因为Cookie是有大小限制的,且信息存储在浏览器中不安全,所以不推荐这种做法

第二种情况,比较麻烦,需要url重定向或一些其他办法

第三种情况,推荐使用这种,但是存在用户禁用Cookie的问题,且因为Cookie不能跨域,所以不能做到跨域资源共享。

Token

Token是一个令牌,本质是对一些用户数据做了个签名。然后会把签名和数据一块发送给服务端,由服务端验证。

Session负载均衡的问题,本质在于服务端要保存session,如果只让每个客户端去保存该多好?可是如果不保存这些session id ,  怎么验证客户端发的session id 的确是服务端生成的呢?所以关键点就是验证。

比如说, 小F已经登录了系统, 我给他发一个令牌(token), 里边包含了小F的 user id, 下一次小F 再次通过Http 请求访问我的时候, 把这个token 通过Http header 带过来不就可以了。不过这和session id没有本质区别啊, 任何人都可以可以伪造,所以我得想点儿办法, 让别人伪造不了。

那就对数据做一个签名吧, 比如说我用HMAC-SHA256 算法,加上一个只有我才知道的密钥,对数据做一个签名, 把这个签名和数据一起作为token , 由于密钥别人不知道, 就无法伪造token了。

这个token 我不保存,  当小F把这个token 给我发过来的时候,我再用同样的HMAC-SHA256 算法和同样的密钥,对数据再计算一次签名, 和token 中的签名做个比较, 如果相同, 我就知道小F已经登录过了,并且可以直接取到小F的user id(用户信息) , 如果不相同, 数据部分肯定被人篡改过, 我就告诉发送者: 对不起,没有认证。

Token 中的数据是明文保存的(虽然我会用Base64做下编码, 但那不是加密), 还是可以被别人看到的, 所以我不能在其中保存像密码这样的敏感信息。

SSO 单点登录

单点登录,通常用于企业内部系统,在多个应用系统中,只需要登录一次,就可以访问其他相互信任的应用系统。在移动端,多用于第三方登录,例如微信登录、苹果登录等。

前文说过,现在比较通用的登录方案是使用Session+Cookie的方案,但是这种方案不可以跨域使用。也就不能实现真正的单点登录。

这里我们就要说一说CAS流程了,这个流程是单点登录的标准流程。

上图是CAS官网上的标准流程,具体流程如下:

  1. 用户访问app1系统,app1系统是需要登录的,304重定向至sso认证中心,并将自己的地址作为参数。
  2. 跳转到CAS server,即SSO登录系统,以后图中的CAS Server我们统一叫做SSO系统。 SSO系统也没有登录,弹出用户登录页。
  3. 用户填写用户名、密码,SSO系统进行认证后,将登录状态写入SSO的session,浏览器(Browser)中写入SSO域下的Cookie(全局Session)。
  4. SSO系统登录完成后会生成一个ST(Service Ticket),即Token令牌,然后304重定向到app1系统,同时将ST作为参数传递给app1系统。
  5. app系统拿到ST后,从后台向SSO系统发送请求,验证Token是否有效。
  6. 验证通过后,app1系统将登录状态写入session并设置app1域下的Cookie(局部Session)。

至此,跨域单点登录就完成了。以后我们再访问app1系统时,app1就是登录的。接下来,我们再看看访问app2系统时的流程。

  1. 用户访问app2系统,app2系统没有登录,重定向到SSO系统。
  2. 由于SSO系统之前已经将SessionId写入Cookie(全局Session),会自动带入,SSO系统拿到SessionId,判断已经登录了,不需要重新登录认证。
  3. SSO生成新的ST Token令牌,浏览器跳转到app2系统,并将ST作为参数传递给app2。
  4. app2拿到ST,后台访问SSO,验证ST是否有效。
  5. 验证成功后,app2将登录状态写入session,并在app2域下写入Cookie(局部Session2)。

这样,app2系统不需要走登录流程,就已经是登录了。SSO,app1和app2在不同的域,它们之间的session不共享也是没问题的。

移动端的第三方登录,原理是一样的。这里以微信登录为例,在客户端登录,跳转到微信页面,输入用户名密码登录成功后,微信客户端会返回一个Token令牌给到App客户端,App客户端将Token令牌发送给App的服务端,服务端拿到Token后,会去微信的后台验证Token,如果验证成功,即登录成功,App服务端根据自己的策略处理即可。

你可能感兴趣的:(Session Cookie Token SSO单点登录)