自己写SSO-介绍(一)

首先什么是SSO?

单点登录SSO(Single Sign On),就是我们的多个系统共用一套登录,在其中一个系统登录后,其他系统可以不用登录(表面看上用户不用登录,但是系统内部需要验证用户信息,这就是SSO要做的工作),可以直接登录其他系统操作。

SSO 的实现机制大体分为 Cookie 机制和 Session 机制两大类。

认证机制

举例:一般登录系统,要提供用户名和密码,通过表单发送到服务器去验证,以tomcat为例,浏览器第一次请求,会在服务端生成一个会话,会话保存在服务端并生成会话id,即JSESSIONID,如果登录成功,response把JSESSIONID返回到浏览器,浏览器保存到cookie,下次请求都会带着这个JSESSIONID参数,服务器校验是否信任请求,当然如果JSESSIONID没过期是不用再登录,这是Session机制(会话跟踪)。这时候JSESSIONID就是浏览器与服务器之间的信物。O(∩_∩)O~~

上面是我们最简单的单体应用登录场景。

某服务的服务器不是一台呢?是集群,怎么办?当然可以把登录信息保存到第三方缓存,比如redis或者memcache,可以解决,就是session共享问题了。

认证存储

上面情况,使用浏览器cookie,需要考虑cookie的安全问题,再就是跨域问题(后面会介绍)

由于HTTP协议本身是无状态的,所以产生了Cookie机制和Session机制,来保存浏览器和服务器之间的状态。

  • 区别就是存储方式:cookie是在浏览器存储,session则是在服务端,是服务端机制。

  • 联系:它们直接联系就如上面的例子,session依赖cookie存储JSESSIONID,来完成服务端认证。

    上面的例子就是用的session机制。

cookie分类
  • 会话cookie

    不设置过期时间,则表示这个cookie生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。这种生命期为浏览会话期的cookie被称为会话cookie。会话cookie一般不保存在硬盘上而是保存在内存里

  • 持久cookie

    设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie依然有效直到超过设定的过期时间

cookie属性
  • name字段 cookie名
  • value字段 cookie值
  • domain字段 能使用cookie的域名
  • parth字段 访问此cookie的页面路径, 比如domain是abc.com,path是/test,那么只有/test路径下的页面可以读取此cookie。
  • expires/Max-Age字段 此cookie超时时间,若设置其值为一个时间,那么当到达此时间后,此cookie失效。不设置的话默认值是Session,意思是cookie会和session一起失效。当浏览器关闭(不是浏览器标签页,而是整个浏览器) 后,此cookie失效
  • Size字段 此cookie大小。
  • http字段 cookie的httponly属性。若此属性为true,则只有在http请求头中会带有此cookie的信息,而不能通过document.cookie来访问此cookie。
  • secure字段 设置是否只能通过https来传递此条cookie
cookie共享
  • 非顶级域名,如二级域名或者三级域名,设置的cookie的domain只能为顶级域名或者二级域名或者三级域名本身,不能设置其他二级域名的cookie,否则cookie无法生成。
  • 顶级域名只能设置domain为顶级域名,不能设置为二级域名或者三级域名,否则cookie无法生成。
  • 二级域名能读取设置了domain为顶级域名或者自身的cookie,不能读取其他二级域名domain的cookie。所以要想cookie在多个二级域名中共享,需要设置domain为顶级域名,这样就可以在所有二级域名里面或者到这个cookie的值了。
  • 顶级域名只能获取到domain设置为顶级域名的cookie,其他domain设置为二级域名的无法获取。

引入问题

我们要用SSO解决什么问题呢?就是有多个子系统,多个应用组成的系统,用户不可能一个系统一个系统的登录或者注销,是不可接受的。

好了,有了上面cookie的基础,可以了解的,我们要基于cookie写sso的话,肯定要操作cookie,其中很重要的一个属性就是domain,因为sso是要服务多个系统,简单的只有一个域名,复杂会有多个域名。

同一个域名下不同的系统

如果是同一个域名下不同context path下的系统,是可以共享同一个domain下的cookie的。

同一个根域下不同的二级域名的系统

可以共享根域下的cookie,写到根域就可以

不同域名下的系统
  • 通过重定向到多个系统,写cookie,性能比较差
  • 引入独立的站点域名:passport.xxx.com或者sso.xxx.com
    • 请求系统A一个需要验证的页面(拦截器拦截后),A获取Session的状态,如果没有登录,A向浏览器发送重定向到sso.xxx.com的命令,并在请求后面添加returnUrl=A.xxx.com,之后浏览器请求sso.xxx.com,sso获取sso.xxx.com域下的带有身份验证的cookie,或者token,如果不存在,说明需要登录,直接跳转到sso.xxx.com下的登录页面,统一管理登录。
    • 如果在sso登录成功,写入sso.xxx.com域的cookie身份信任信息,发送浏览器重定向A系统指令,浏览器发起returnUrl中请求,带着token,A系统获取token后,调用sso.xxx.com的rest验证接口,如果验证通过,拦截器通过,写入A系统session登录信息,否则跳转到登录页面。
    • 请求B系统,还是获取session状态,如果没有登录,拦截器重定向到sso.xxx.com登录,sso.xxx.com从cookie中获取到token后发现已经登录,将带着token,重定向returnUrl,系统B发现,请求中token,拿到token,调用sso.xxx.com系统的rest接口验证token,验证成功后,写入Session登录成功,拦截器通过。
    • 一旦用户通过该单点登录模型登录到站点上,请求任何需要验证的页面都会内部重定向到SSOsite验证cookie和提取用户token,然后将请求的页面发送给浏览器输出
    • 退出和注销,请求任一系统注销请求,重定向到sso.xxx.com,验证身份后,返回token,并带着token,请求sso的销毁接口,sso验证token有效,销毁token,并发起其他注册系统销毁本地会话。
坚持技术分享,您的支持将鼓励我继续创作!