谈谈SSO单点登录的设计实现

谈谈SSO单点登录的设计实现

本篇将会讲讲单点登录的具体实现。

实现思路

其实单点登录在我们生活中很常见,比如学校的网站,有很多个系统,迎新系统,教务系统,网课系统。我们往往只需要登录一次就能在各个系统中被认定为登录状态。

这是怎么实现的?我们需要一个认证中心,一如学校网站也有一个统一认证中心,也就是我们的SSO的Server端。在每个系统也就是Client端,我们只要判断已经在这个认证中心中登录,那我们就会被设置为登录状态。

再来就是最后一个问题了,我们判断在认证中心登录后,怎么在其他系统中也登录?

这个问题其实就是单点登录中最麻烦的问题了,也就是如何传播我们的登录状态。

我们可以分为两个情况Cookie共享传播状态,url参数传播状态。

Cookie共享传播状态

第一种情况:我们的认证中心和其他系统是在一个域名下的,认证中心为父域名(jwxt.com),其他系统是子域名(yx.jwxt.com),或者是同一IP不同端口的情况,我们的服务端通过cookie去判断是否登录。

在这种情况下我们只要在认证中心登录成功的时候设置Cookie,当然设置Cookie的时候也要注意设置好你的Cookie参数。

要注意设置的参数是dominpath 。这两个参数值决定了Cookie的作用域。domin 要设置为父域名(.jwxt.com)。当然还要注意一个SameSite 参数,不能设置为None。(如果为None,你在baidu.com登录,在example.com网站如果你点击了 https://baidu.com/delete链接,会带着你在baidu.com的Cookie访问。)

设置完Cookie,子域名的系统也有了Cookie,自然就会被服务端判断为登录状态。

简而言之,就是利用Cookie共享来实现登录状态的传播。

url参数传播状态

第二种我们的认证中心和其他系统不在一个域名下的,或者是不同IP的情况。

为了安全浏览器限制cookie跨域,也就是说第一种方法就不管用了。

这种情况可以通过传播参数来实现,也就是在认证中心登录后带着 登录凭证(token) 重定向到对应的Client页面,然后我们的前端就可以用js获取到url中的token进行存储(设置到Cookie或者localstorage等方式),之后我们的服务端只需要通过这个token就可以判断为登录状态了。

当然,为了安全我们往往不会直接传递凭证,而是传递一个校验码ticket,然后前端发送ticket到服务端校验ticket,校验成功,就进行登录,设置Cookie或者存储token。

流程

接下来我们梳理一下流程,一下Client为需要单点登录的系统,Server为统一认证中心。

Cookie共享传播状态

  1. 用户在Client1,如果没有登录,跳转到Server,判断在Server是否登录,如果判断没有登录,要求登录,登录成功后设置Cookie,跳转Client
  2. Client1登录成功

如果之后在Client2页面,由于共享Cookie,当然也是登录状态。

url参数传播状态

  1. 用户在Client1,判断没有登录,跳转到Server,判断在Server是否登录,如果没有登录,要求登录,登录成功后设置Cookie,带着ticket跳转Client。
  2. 到了Client1,前端通过参数获取到ticket,发送到服务端,服务端校验ticket获取登录id,设置Cookie进行登录。

之后在Client2页面

  1. 用户在Client2,判断没有登录,跳转到Server,判断在Server是否登录,这时候判断为登录,带着ticket(或者token)跳转Client。
  2. 到了Client2,前端通过参数获取到ticket,发送到服务端,服务端校验ticket获取登录id,设置Cookie进行登录。

如果不使用ticket校验就直接存储传播过来的登录凭证即可,当然如果你不存储到Cookie,记得在请求后端服务的时候带上token。

ticket校验

再说说ticket校验

ticket校验根据情况也可以分为两种,一种情况是Server和Client的后端共用的同一个Redis或者Redis集群,可以直接向Redis请求校验。如果后端用的Redis不同,可以发送http请求到Server端在Server端校验。

到此,单点登录就完成了。

当然在以上描述中的Cookie你也可以不使用,使用Cookie主要是方便,在请求后端时会自动发送。你只需要存储到localstorage/sessionstorage等地方,请求后端的时候记得get然后带上即可。