帮你理清单点登录十个关键问题

帮你理清单点登录十个关键问题

PS本文讲的是SSO单点登录,不是指用户只能一处登录, 把账号顶下线的单设备登录

单点登录系统适用的场景有哪些?

  • B端,公司需要一个员工统一登录平台,一个账号登录内部应用、产品后台
  • C端,用户需要一个账号通行公司下多个产品,比如一个QQ可以登录腾讯网、IM、QQ音乐等

单点登录有哪些协议?

  • cas
  • oidc
  • saml
  • 其他和自定义协议…
    其中cas协议官方服务端实现是java,对其他语言不友好,比如php的sdk写的奇烂无比,saml比较复杂

单点登录大概原理是什么?

各种协议基本原理都类似

  1. sso客户端重定向到sso服务端,带上客户端站点地址给sso服务端用户重定向
  2. sso服务端重定向(未登录则先登录)回sso客户端,并且在重定向地址query中添加一个与当前用户关联的票据(cas为ticket,oidc协议为code)
  3. sso客户端使用在后端发起http请求,用票据向sso服务端交换用户信息
  4. sso客户端在本系统查询用户信息(不存在则新增),并且写入登录状态

依靠共享SESSION实现两个共享登录状态是单点登录吗?

单点登录一定是异系统,每个子系统都有自己的用户表,而共享SESSION往往是一个强关联的系统,甚至就是一张用户表

内部用的SSO和C端SSO设计上有什么区别,是否通用?

两种场景需求不同,设计上往往有较大差异

举例新员工入职录入SSO系统后,内网部署的gitlab中是没有员工的系统的,员工首次登录gitlab后,gitlab从sso拉取到了员工信息,这没有问题
但是财务发工资的时候却会发现财务系统中没有这个员工的信息,因为员工没有登录过财务系统,甚至财务系统压根没有员工登录的功能,所以,企业内部用的SSO一般需要上下游同步功能,比如公司使用了企业微信、丁丁、飞书、ldap,sso需要把里面员工信息同步过来,同时,新员工录入信息,修改信息后,需要立即同步至公司内其他系统。

而在C端,这个需求往往不强烈,举例试想以下腾讯有十数亿用户,如果腾讯新上线了一个小众产品,本身只有几十万用户,但是每天把十几亿不使用这个小众产品的用户修改昵称、头像等事件都同步到这个系统,就显得没有必要。

内部SSO除了接入自研应用,还会接入各种商用系统、开源系统、saas系统, 这些系统往往由不同厂商开发,五花八门,所以内部用的sso往往必须支持cas和oidc,几行配置就可以用员工账号登录这些系统,而c端往往只使用一种统一的协议,方便实现和维护

OAuth2和OIDC区别是什么,OAuth2能不能用来做SSO?

  • code交换token时,OIDC比OAuth2多返回了一个jwt格式id_token,access_token用于授权,id_token用于认证。

  • OAuth2技术上可以搞成sso,很多人也确实在这样做,但不该!!
    OAuth2的目的是授权,比如你微博授权登录某站,某站就能代替你发微博
    电商网站OAuth2授权给第三方工具,第三方工具就可以通过OAuth2代替你完全某些工作,比如上货,整理商品。
    这是OAuth2设计出来的主要目的,把你在本站本身具有的功能权限授权给第三方。

  • 你应该使用OIDC来代替OAuth2,从id_token中解析用户信息,和sso客户端中的用户信息关联,完成登录,而不是通过oauth2的access_token再去拉取一次用户信息

  • 如果你接入过微信,就会发现腾讯为了防止你获得用户关系链,不同appid通过微信OAuth2获取到同一个微信用户的openid是不同的,oauth2做sso会有很多潜在问题,尤其是同步退出问题

怎么同步退出所有站点?

举例cas协议中,sso、 client1、 client2都处于登录状态,点击client1退出重定向指sso退出,此时client2还是登录状态

  • 方案1: 异步通知退出
    sso服务端退出时,启动一个异步队列任务,向当前登录用户当前登录session发放过ticket的cas client发送http通知,携带ticket,sso客户端收到通知后,找到使用使用该ticket登录的用户session_id,使session_id失效

大致原理如此,如果是自定义协议可以直接在或者票据或者或者用户信息时,携带session_id给sso服务端,sso服务端退出时直接http通知sso客户端把该session_id失效即可
sso服务端可以在redis存一个含当前session_id的hash,hash里存sso client_id科client session_id即可,退出时把这个hash拉出来通知即刻

不过不推荐这个方案,略复杂、可靠性不高

  • 方案2: 同步通知退出

      sso退出时,直接遍历请求sso client的退出页面即可,js也行,iframe也行
      这个方案也是大厂都在用的方案,比如新浪家退出是js请求https://login.sina.com.cn/sso/logout.php,返回一个数组
      ```
          [
            "https://passport.weibo.com/wbsso/logout",
            "https://passport.krcom.cn/sso/crossdomain?action=logout&entry=krvideo",
            "https://passport.sina.cn/sso/crossdomain?action=logout",
            "https://passport.weibo.cn/sso/crossdomain?action=logout"
          ]
      ```
      然后js轮流请求返回的这些退出页面实现退出
    
      小米退出则是跳转至https://account.xiaomi.com/pass/logout,然后把各个域名下的退出页面作为图片调用
      https://logout.xiaomi.net/
      https://logout.xiaomi.cn/
      https://logout.miui.com/
      https://logout.xiaomi.com/
      https://logout.mi.com/
      https://logout.duokan.com/
      https://logout.miwifi.com/
      https://logout.mipay.com/
      https://i.mi.com/logout
      https://credit.mixiaojin.com/gw/mixiaojin/logout

如果一个页面不需要登录也可以访问,即不会强制跳转,如何从sso获得登录信息?

比如cas是需要跳转cas/login才能拿到票据交换用户信息的,如果一个to c的网站,用户不登陆就可以浏览新闻,此时新闻站不知到sso登录,也不会强制跳转到sso去

这种情况在B端不是问题,毕竟内部系统往往都需要登录,或者就让他自己点以下跳转,在C端体验就比较差了,
常见方案是sso登录时除了session_id,还有另外在根域名下写一个cookie,记录自己已经处于登录状态,新闻站读取到这个cookie,
知道sso已经登录则与sso交互进行登录,如果没有这个cookie,则继续游客状态,cookie可以加密一下防止篡改

如果你的站点处于多个根域名下,则使用上面同步退出的方案,登录时请求多个域写登录状态标识,伪例子:

你在 account.taobao.com/login 登录,成功后这个页面js调用

我不想跳转登录,想弹窗登录如何做?

cas和oidc都是跳转登录的,你可以像百度和微博一样,自定义协议实现

比如从百度首页,弹窗登录后返回一个链接数组,js依次请求
```
https://baike.baidu.hk/common/api/crossdomain?bdu={bdu}&t={timestamp}
https://www.yoojia.com/sync/crossdomain?bdu={bdu}&t={timestamp}
https://user.hao123.com/static/crossdomain.php?bdu={bdu}&t={timestamp}
```
其中bdu是加密票据,crossdomain页面解密这个bdu之后,根域名下写入名为BDUSS的cookie

任意一个百度站点,如贴吧检测到BDUSS这个cookie后,拿BDUSS在发送后端请求向https://passport.baidu.com交换用户信息,通过唯一id查询用户
如果贴吧没有这个用户写入用户表后再登录,有这个用户则直接登录,写入贴吧站自己的session_id

如果贴吧自己的session_id还处于登录状态,但是BDUSS没有了 说明百度的sso(passport.baidu.com)已经退出了,则贴吧也退出自己的账号系统即可

重点: 百度和新浪均为这个方案,但是有缺陷的,比如你在登录后把新浪网的cookie清空,此时你就会发现新浪退出了,非同域的微博却还登录着的,除了再输密码登录一次别无它法,而必须跳转获取票据的方案均不存在该问题。
重点2:由于chrome更新了cookie策略,跨域设置cookie必须samesite设置成none,而samesite的前提是cookie设置secure,即只有https可以读取,所以除非你的所有站点都使用https,否则最好使用跳转方案

如何同步用户信息?

sso除了登录名、密码、往往还集中储存头像、邮箱、手机号等用户信息
假设贴吧登录状态是一个月,但是头像在拿BDUSS向passport.baidu.com交换用户信息时就已经拿到了,如果不退出的话贴吧和passport.baidu.com在这一个月内也不会再交互
如果用户修改了头像,贴吧会一直是旧头像,除非退出重新登录拉取

在cas、oidc中都没有关于这部分的定义,因为他们只管认证,所有用户资料的同步不管你是使用cas、oidc还是自定义协议实现的sso,都要自己设计同步方案。

可以客户端主动拉取也可以sso主动推送,最好每个sso客户端站点都可以独立配置自己要订阅的事件和信息变更,没有必要做全量推送。
本作品采用《CC 协议》,转载必须注明作者和本文链接
:) wink
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!