单点登录方案调研与实现

作用

在一个系统登录后,其他系统也能共享该登录状态,无需重新登录。

演进

cookie → session → token →单点登录

可以实现浏览器和服务器状态的记录,但Cookie会出现存储体积过大和可以在前后端修改的问题

Session

为了解决Cookie的数据敏感问题,Session应运而生。

  • 常见的实现方式是基于Cookie。只将口令放置Cookie,通过口令实现前后端数据的映射,大部分数据存储于服务器的session中,这里会有一个全局sessions去存储每个用户的session,并设置每个的有效期,一般20分钟。超时则重新生成和更新全局sessions。
  • 分布式问题:通常服务器是集群,用户的请求会走到负载均衡,不一定打在同一台登录请求的机器上,那不就 session 失效了吗
    • 解决方案:
      • 第一种,把 session 集中存储,给个独立的 redis 或普通数据库
      • 第二种,将相同 ip 请求的负载均衡都打在同一台机器上。
    • 通常是第一种,因为第二种的同一台机器会出现请求过多宕机的问题。

token

  • 解决场景

    session 的维护给服务端造成很大困扰,我们必须找地方存放它,又要考虑分布式的问题,甚至要单独为了它启用一套 Redis 集群。有没有更好的办法?------token

    登录场景不需要往 session 存太多东西,那为何不直接打包到 cookie 中呢?这样服务端就不用存了,每次核验 cookie 带的 token 有效性就可以了,还可以存一些轻量的信息。

  • HTTP 头部

    token 认证则不需要后台保存,token一般放在HTTP请求头的 Authorization 中

  • 流程

    • 输入用户密码,通过的话,服务器返回 token
    • 浏览器每次携带该 token 去请求数据

来源

最早起源于多服务器间 session 数据一致的问题。

方案

关键如何让 Session ID(或 Token 在多个域中共享)

不同的项目情况,适用不同的方案,适合的才是最好的

按照域名划分方式分类:

同主域

一个企业,一般情况下只有一个域名,通过二级域名区分不同的系统。

二级域名不同也算跨域。当协议,域名,端口其中一个不同时,就算跨域了。

例如 aliyun.com,其他业务系统分别为:a.aliyun.comb.aliyun.com ,要做单点登录,需要一个登录系统,叫做 account.aliyun.com ,我们只要在 acount.aliyun.com 登录了,a.aliyun.comb.aliyun.com 也登陆了

实现

  • 方法一: Root Cookie 方式

    • 原理:同一域名下的不同子域名属于同一主域名,主域名下的 cookie 在不同子域名中都是可见的。

    • 将得到的 ticket 写入根 Cookie 里,通过修改 domain。这一步前后端择一写即可

      利用二级域名写一级域名的 Cookie, acount.aliyun.com 登录后,可将 cookie 的域设置为顶域,即 .aliyun.com ,这样所有的子域都可以访问到顶域的 cookie

      • 前端:react 和 vue 都有 js-cookie 包

        jsx 复制代码
        import Cookies from 'js-cookie'
        Cookies.set('key', 'value', { domain: 'localhost' })

        前提:后端没有配置 httpOnly,否则无法通过 document.cookie 方式读写,但有些浏览器仍支持写入。

      后端:java

      jsx 复制代码
      Cookie cookie = new Cookie("key", "value");cookie.setDomain('.example.com')

      无需在 domain 后加上端口号。设置完后,同主域名的网址打开浏览器的存储,便能看到 cookie 了。

    • 总结:实现简单,不支持跨主域名的方式

  • 方法二:postMessage + iframe 方案,无需后端参与

    • 可以实现同主域和不同主域,不同的是同主域的实现即便关闭后,再打开也没问题。不同主域的,关闭后就不会保存了。监听 message 的同时,在 postMessage 后,窗口就会触发了。

    • cross-storage 库,实现了对该方案的封装

      • 原理:类似中转站,所有的登录信息的存储或获取都通过该中转站
      • 使用注意
        • 如果无法连接成功的,可以考虑将初始化代码放入 html 中,并单独开启一个服务器(例如小型 node),用来对该页面的访问。

        • CrossStorageHub.init 时,localhost 和 域名都要写上

          javascript 复制代码
          CrossStorageHub.init([
          	{origin: /.*localhost:808\d$/, allow: ['get', 'set', 'del']},
              {origin: /.*data.com:300\d$/, allow: ['get', 'set', 'del']}
          }]
    • 缺陷:Safari 浏览器不兼容该方案

      • 原因:postMessage + iframe(cross-storage)由于 safari 浏览器只支持和 iframe 通信,不支持新窗口通信,无论是通过 iframe.src 带上 token 的 query 还是通过 postMessage 存储到 localStorage 里。新打开一个窗口后,localStorage 里都没有之前的存储值。

      • cross-storage 的文档,也给出了降级方案

        • 可以采用 root cookie 方式
        • 让服务端返回的方式
        • 直接去改变safari浏览器的配置。 (不建议)
        • 跳转的 url 链接带上该 token 的 query,前提是要点击后才能触发。再保存到本地

不同主域

实现:

  • 方法一:

    部署一个 SSO 认证中心,专门负责处理登录请求(登录、登出、获取用户信息、当前用户状态),是单点登录的标准做法。

    类似中转站,所有子系统的登录都要询问一遍这个中转站

    CAS: 基于 SSO 认证中心的开源项目代表,Central Authentication Service 即中央认证服务

  • 方法二:iframe + postMessage 的方式

    同上

相关推荐
炸裂狸花猫6 天前
开源身份认证与访问管理平台 - Keycloak(二)
docker·云原生·容器·kubernetes·开源·keycloak·sso
Cry丶7 天前
架构师实战:Spring Authorization Server 落地企业级“无感” SSO(附设计映射与源码级接口剖析)
spring·spring security·oauth2.0·authorization·sso·无感登录
摇曳的精灵11 天前
Keycloak开源企业级IAM
开源·keycloak·iam·sso
观测云12 天前
观测云集成钉钉 SSO 最佳实践
钉钉·sso·观测云
学习3人组24 天前
单点登录主流实现机制SAML 2.0(Security Assertion Markup Language)
sso
Lim小刘1 个月前
AWS IAM Identity Center 实战操作:从启用、用户、权限集到 SSO 登录
云计算·aws·云安全·sso
阿杜杜不是阿木木1 个月前
authentik开源身份认证与管理平台-介绍与安装(1)
数据库·redis·开源·authing·sso·authentik
總鑽風1 个月前
springcloud2023_alibaba_sso单点登录_授权码模式(已跑通)
springcloud·单点登录·sso·授权码模式
總鑽風1 个月前
springcloudalibaba2021-SSO 单点登录_密码模式
springcloud·alibaba·sso
DexterLien1 个月前
使用开源 Authentik 实现 AWS 单点登录
aws·sso·saml·authentik