需求描述:理解单点登录、登录、以及cookie的使用
维持登录态的几种方式
传统身份验证的方法
HTTP 是一种没有状态的协议,也就是它并不知道是谁访问应用。这里我们把用户看成是客户端,客户端使用用户名还有密码通过了身份验证,不过下回这个客户端再发送请求时候,还得再验证一下。
解决的方法就是,当用户请求登录的时候,如果没有问题,我们在服务端生成一条记录,这个记录里可以说明一下登录的用户是谁,然后把这条记录的 ID 号发送给客户端,客户端收到以后把这个 ID 号存储在 Cookie 里,下次这个用户再向服务端发送请求的时候,可以带着这个 Cookie ,这样服务端会验证一下这个 Cookie 里的信息,看看能不能在服务端这里找到对应的记录,如果可以,说明用户已经通过了身份验证,就把用户请求的数据返回给客户端。
上面说的就是 Session,我们需要在服务端存储为登录的用户生成的 Session ,这些 Session 可能会存储在内存,磁盘,或者数据库里。我们可能需要在服务端定期的去清理过期的 Session 。
基于 Token 的身份验证方法
使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:
1、客户端使用用户名跟密码请求登录
2、服务端收到请求,去验证用户名与密码
3、验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
4、客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
5、客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
6、服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
Cookie
Cookie种类
1、临时Cookie(会话Cookie)
2、永久Cookie
cookie分为两种,一种是硬盘上的,另一种是内存上的,一个网站通常有一个.txt文件来存Cookies,一个Cookie对象最终转换为txt文件中的一条记录。保存在浏览器线程分配的内存中的Cookie对象,在关闭这个浏览器窗口后,就销毁了。导致种类不同是过期时间的设置与否决定的,如果设置了过期时间,那么就会在过期时间未到前一直生效,请求会被携带,除非服务端设置了max-age强制使其失效;而没有设置过期时间,cookie的生命周期只存在于浏览器会话期间,关闭窗口,cookie即消失。
Cookie被携带的条件
同一域名下,存在cookie,浏览器会默认自动发送Cookie给对应的服务器。
普通的ajax(json)请求和jsop跨域请求是默认携带cookie的,而cors跨域请求和fetch请求默认是不携带cookie的。因此,当我们的请求需要携带cookie时,我们就要对cors跨域请求和fetch请求这两中请求方式进行特殊配置处理。
通常我们使用的axios库,也是对XMLHttpRequest这个对象的封装,和ajax请求无异,因为加入了promise,解决了回调的问题。
而fetch请求如果想携带cookie,需要设置header里面的参数,加上credientials: ‘include’;
CORS的方式想要携带cookie,需要设置如下设置
1 | // aixos为例 |
设置Cookie的方式
1、后端设置set-cookie,这种情况下,前端什么也不需要做。相当于服务器端给浏览器发送指令,浏览器自动注入cookie,每次请求都携带cookie信息;
2、前端收到后端返回的信息,设置cookie;
1 | function setDomainCookie(name, value, expiresDays = 60, host) { |
Cookie 分析 && 总结
1、cookie信息自动被请求携带,不限于请求后端数据的请求,即使是刷新页面,图片,css,js,也都会携带本地的cookie信息,这无疑相当于浪费了请求头的资源;
2、cookie是不允许跨域传输的,所以在本地localhost发送的请求是不会被携带到请求头里的,这样就会有问题,如果很多请求都需要验证权限,而开发环境又无法携带cookie信息,就会带来联调上的困难;
3、cookie中能够存储的数据有限,不同的浏览器限制大小不一样。
综上,在实现自动登录时,前端收到服务端返回的token,可以存到localstorage里,然后塞入请求头中,所有对于数据的请求都会携带此头部字段,虽然localstorage没有过期这一概念,我们可以自己手动设置,每次发送请求前都判断一遍是否过期,如下:
1 | // 存入 |
设置请求头:
1 | // 以axios实例为例 |
题外记,如果存有登录信息的cookie文件,被复制到另一台设备的指定目录下,去访问这个cookie对应的网站,是不是也能正常访问呢?
我的理解是可以的,或者换一种方式,我的设备上的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本身不安全。
因此,我们需要一种全新的登录方式来实现多系统应用群的登录,这就是单点登录。
相比于单系统登录,sso需要一个独立的认证中心,只有认证中心能接受用户的用户名密码等安全信息,其他系统不提供登录入口,只接受认证中心的间接授权。间接授权通过令牌实现,sso认证中心验证用户的用户名密码没问题,创建授权令牌,在接下来的跳转过程中,授权令牌作为参数发送给各个子系统,子系统拿到令牌,即得到了授权,可以借此创建局部会话,局部会话登录方式与单系统的登录方式相同。
所有系统(可能是不同域下的系统)共享一份相同的已验证的、安全可靠的信息。即SSO系统让不同Domain拥有一份相同的cookie,当用户访问A系统时,在A系统验证成功后,在其域下设置一份cookie,当访问B系统时,再跳回SSO,然后在B所处的域下复制一份cookie。结果就是,我访问A,A进行验证,验证失败,跳转至SSO,要求我登录,我通过SSO登录,SSO验证成功后生成sessinID,随后将UserInfo( SessionID、ID和口令)存储到公共缓存C 中,跳转至A(携带SessionID),并允许我访问A;我保存UserInfo ( SessionID ) 至 cookie;
我访问B,B进行验证,失败跳转至SSO,SSO将触发我请求SSO将验证信息随请求一并发给SSO,经SSO验证成功跳转至B,允许我对B 的访问;使我保存UserInfo( SessionID)至cookie;
问题:(不同域下,请求B系统的验证信息从哪里来?据说是放在顶级域名下的。)
(实际上,我对单点登录只是有一个模糊的概念,后续学习,会继续更新)
欢迎指正!
参考文章:
1、React16新的生命周期函数getDerivedStateFromProps的使用,你也许并不需要派生状态【译】
2、HTTP–Request Headers及Cookies
3、状态保持中的Cookie与Session
4、CORS简介
5、axios的cookie跨域以及相关配置
6、漫谈单点登录(SSO)
7、单点登录原理与简单实现
8、单点登录SSO:概述与示例