04月25, 2018

node服务中如何接入SSO

今天我们来聊聊如何使用nodejs来接入单点登录。

什么是单点登录

我们先来说说什么是单点登录。单点登录应为名称叫 Single sign-on简写为SSO,它是一个用户认证的过程,允许用户一次性进行认证之后,就访问系统中不同的应用;而不需要访问每个应用时,都重新输入密码。IBM对SSO有一个形象的解释“单点登录、全网漫游”。

Single sign-on (SSO) is a property of access control of multiple related, yet independent, software systems.

翻译一下,单点登录是一个 关联 多个独立的软件系统访问控制 的属性。

换成大白话,就是SSO可以统一管理多个独立的系统的登录服务,实现的效果是,在所有接入SSO的众多系统中,只要在一个系统中实现登录,那么其他系统就可以进行免登陆访问。

SSO实现方式有:

  1. 共享Cookies
  2. Broker-based
  3. Agent-based
  4. Token-based
  5. 基于网关
  6. 基于SAML

其中最常见的是 共享Cookies。

SSO原理分析

接下来我们来梳理一下SSO的实现原理,这有助于你下一步的实现。 alt

整体的流程图就如上图, 接下来我们来梳理一下步骤,为了方便起见,接下来我以我的个人域名举例说明。

1、URL(www.imwineki.cn/test)请求会打到 www.imwineki.cn 的server上,这时server收到请求后,判断网站是否需要登录,如果不需要就直接返回 index.html 页面

2、当server判断当前需要登录的时候,则获取当前网站域名 www.imwineki.cn 下的cookie 中的 T-ticket 值。

  • 如果获取 T-ticket 成功,则server 将 T-ticket 发送给 Auth 认证服务去做身份验证。此时页面URL依然是:www.imwineki.cn/test。 Auth 服务获取到 T-ticket 值后对比redis中存储的 T-ticket值进行身份验证。
    • 如果Auth验证成功,则直接返回正确信号,Server接受到 T-ticket 正确后更新 Cookie 的过期时间,然后重定向到对应的路由上,返回页面,流程结束。
    • 如果Auth验证失败,则302重定向到SSO 服务,此时URL变成了:passport.com?service=http://imwineki.cn/test。
  • 如果获取 T-ticket 失败,则直接302重定向SSO服务。并将当前来源网站域名及路由携带过去。此时页面的URL变成了:passport.com?service=http://imwineki.cn/test

3、当服务重定向到SSO服务后,SSO服务获取当前域名下的Cookie,也就是 passport.com 下的cookie。从该域名下的Cookie中获取 P-ticket 值。

  • 如果获取 P-ticket 成功,则SSO服务将 P-ticket 发送给 Auth 认证服务去做身份验证。此时页面的URL依然是: passport.com?service=http://imwineki.cn/test
    • 如果Auth验证成功,则填充用户信息(用户名、密码)
    • 如果Auth验证失败,则需要用户填写用户信息(用户名、密码)
  • 如果获取 P-ticket 失败,则需要用户填写用户信息。

4、用户填写登录信息后进行登录,SSO服务会生成 新的 T-ticket 和 P-ticket ,然后发送给 Auth 服务备份ticket。并将P-ticket 存入 SSO cookie下,将携带 T-ticket 信息 302 到 原服务 中,此时 URL 是:passport.com?service=http://imwineki.cn/test?ticket=`${T-ticket}`。

5、imwineki.cn 的 server 收到请求后,会获取到 T-ticket 值,然后将 T-ticket 值设置到 imwineki.cn的域名下。

6、然后将路由重定向到主域名下,此时URL是:Imwineki.cn。之后,再次重定向到对应的路由下,此时URL是:http://imwineki.cn/test,整个流程完成。

alt

下面,我们模拟两个系统通过SSO服务登录。假设现在有两个系统,一个是 A.com ,另一个是 B.com。现在我首次输入A.com的链接,这是A.com 的 server 并不能获取到该域名下 cookie 的 T-ticket 值,所以将服务 302 到 SSO 服务,SSO 服务无法获取cookie中 P-ticket值, 发现我不曾登陆过SSO系统,于是让我填写用户名和密码,我填写后点击登录,这时候我就有了SSO登录记录,SSO会将新生成的ticket发送给Auth服务注册,页面重新 回跳到 A.com,现在我可以自由的访问 A系统了。

这时A系统有一个B系统的入口: B.com/list。我点击了这个按钮,页面跳转到 B.com/list,这时B.com 的 server 获取 B.com 域名下的 T-ticket 时,发现并没有获取到,于是 302 到 SSO 服务,SSO 服务受到请求后,获取 自己域名下cookie 的 P-ticket 值,可以成功获取到刚才登录A系统时注入的值,接下来去Auth 服务验证我的身份,发现身份正确,于是将用户名和密码填充进去,我点击登录按钮,验证成功后,会自动跳转到B.com/list,现在我就可以自由访问B系统。

接下来,我发现B系统中,有一个A系统的入口:A.com/list。我点击了这个按钮,页面跳转到 A.com/list, 这时A.com 的 server 获取 A.com 域名下的 T-ticket 时,可以成功获取到。于是将 T-ticket 发送给Auth 服务进行身份验证,Auth验证成功,实现了免登陆查看。

在node server中接入单点登录服务

接下来,我们在node中实现一下以上的过程,这里我们只模拟 系统服务代码,SSO服务代码这里不赘述。

function login(){
    // 获取当前域名下的 cookie
    const ticket = query.ticket || body.ticket
    //获取路由
    const route = query.route || body.route
    //拼接来源服务 URL
    const service = `http://www.imwineki.cn?route=${route}`
    //SSO服务 URL
    const redirectUrl = `passport.com?service=${service}`

    // 如果无法获取ticket,302到SSO服务
    if( !ticket ){
        ctx.response.redirect(redirectUrl)
    }
    //到Auth服务验证 ticket,设置 cookie
     request(`Auth Service?ticket=${ticekt}&service=${service}`).then((ticket)=>{
        setCookie(ticket)
    }) 
}

关于 CAS

CAS 是 Yale 大学发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登录方法。

感兴趣的小伙伴可以戳这里了解CAS内部原理

本文链接:https://www.imwineki.cn/post/ssonode.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。