🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## SSO 我们知道如果要登录系统,就是需要输入用户名与密码,由服务器来做验证,验证通过之后就建立session, 然后把session id通过cookie发给人类的浏览器,下次人类再访问URL的时候,会把cookie一并传过来,这样系统就知道他们登录过了。 此时如果一个公司有多个系统,对于同一个用户,可能密码还不一样,能不能**在一个地方登录一次,就可以访问所有的系统了?** 有人可能会说,登录其实就是cookie,如果把cookie共享起来不就可以了? 事实上没那么简单 ,因为cookie是不能**跨域**的,a.com产生的cookie,浏览器是不会发到b.com上去,所以共享cookie方案不管用。 不过对于同一个公司内部的系统,完全可以统一到一级或者二级域名之下, 比如 xxx.company.com, 但是在登录前后端没有保存session,所以当cookie发过来之后,内存没有数据,无法知道之前是否登录过,当然谈不上验证。 ![](http://p8a6vmhkm.bkt.clouddn.com/picgo20181023142346.png?picgo) 那么既然有共享cookie,那么session是否可以共享呢? 众多系统, 架构不同,语言也不同, 共享 session 太麻烦 ## token 我们可以同样借助于cookie,比如用户在报销系统登录了,可以在cookie中写个token,用户访问别的系统的时候,就把token带过去,那个系统验证一下token,如果没问题,就认为它已经登录了。 ![](http://p8a6vmhkm.bkt.clouddn.com/picgo20181023142756.png?picgo) 每个系统在生成token的时候,需要对数据做个签名,防止篡改。 ![](http://p8a6vmhkm.bkt.clouddn.com/picgo20181023143422.png?picgo) - 生成签名:通过header与userID,使用hash算法和密钥生成签名,并且把这个签名作为token数据一部分 - 收到token,再利用相同算法计算签名,与发过来的相比,如果相等,说明登录过,直接取出userID即可。 这里面的问题在于算法和密钥大家得一致,而且密钥的分发可能存在风险。 而且token里面放了一个userID,但是每个系统的userID都不一样,拿过来没有任何用。 ## 统一认证中心 可以建立一个统一认证中心,所有用户注册和认证都在这里做。 那么认证中心如何通知每个系统用户已经认证呢? 比如用户先访问系统`www.a.com/pageA`,如果系统发现用户没有登录,需要把它**重定向**到认证中心[www.sso.com/login?redirect=www.a.com/pageA](www.sso.com/login?redirect=www.a.com/pageA) > redirect后面的url是表示,认证通过之后,还需要重定向回来 浏览器放访问到了认证中心,认证中心就会让用户去登录,登录成功之后,认证中心需要: - 建立一个session - 创建一个ticket(随机字符串) - 再重定向到系统A处,url带着ticket:[www.a.com/pageA?ticket=T123](www.a.com/pageA?ticket=T123), 同时cookie也会发给浏览器,比如set cookie: ssoid=1234, sso.com 你可能会说,这个cookie对系统A没有任何用处,因为跨域不能访问? cookie是sso.com的,所以肯定没有用,浏览器只是会保存下来。 但是ticket完全可以用来向认证中心再次做验证,主要作用是防止有人伪造。 ![](http://p8a6vmhkm.bkt.clouddn.com/picgo20181024094104.png?picgo) 然后浏览器会再次访问[www.a.com/pageA?ticket=T123](www.a.com/pageA?ticket=T123), 然后系统A拿着token,去问认证中心,如果认证中心说这个他们发的,就可以认为用户在认证中心登录过了。 此时系统A就为浏览器建立session,返回pageA这个资源。 同时,系统A还需要给浏览器返回一个cookie,这是属于系统A的cookie(之前的是SSO的cookie) ``` set cookie:sessionid=xxx,a.com ``` > 注意,浏览器实际有两个cookie,一个是系统A发的,一个是认证中心发的 如果用户要再访问系统A的另一个受保护的页面,[www.a.com/pageA1](www.a.com/pageA1) , 还需要去认证中心登录吗? 不用,因为系统A已经给浏览器发过自己的cookie,所以浏览器会把这个cookie带过来,这样就知道它登录过了。 ![](http://p8a6vmhkm.bkt.clouddn.com/picgo20181024094940.png?picgo) 如果用户访问www.a.com/pageA 时已经通过认证中心登录了,那么再访问www.b.com/pageB 会发生什么状态? 和访问www.a.com/pageA 非常类似,唯一不同的是不需要用户登录了,因为浏览器已经有了认证中心的cookie, 直接发送给www.so.com 即可。 ![](http://p8a6vmhkm.bkt.clouddn.com/picgo20181024095132.png?picgo) 同样,认证中心会返回token,www.b.com 需要做验证 ![](http://p8a6vmhkm.bkt.clouddn.com/picgo20181024095502.png?picgo) 所以,本质上就是一个认证中心的cookie加上多个子系统的cookie而已。 SSO是单点登录,所以还需要有单点退出。用户在一个系统退出来,认证中心需要把自己的会话和cookie干掉,然后当需要通知各个系统,让他们把会话统统干掉,才能实现真正的退出。