单点登录

定义

单点登录(Single Sign-On,简称 SSO。是目前比较流行的企业业务整合的解决方案之一。

是指用户只需要登录一次,即可在多个应用系统中访问受授权的资源。其原理是在用户登录之后,服务器会颁发一个令牌(Token),并将该令牌保存在共享的存储中(例如 Redis、数据库等),然后在用户访问其他应用系统时,该系统会向认证服务器发送请求,如果该用户已经登录过,则认证服务器会颁发一个新的令牌,否则需要用户重新登录。

eg: 淘宝、天猫都属于阿里旗下,当用户登录淘宝后,再打开天猫,系统便自动帮用户登录了天猫,这种现象就属于单点登录。

实现

方式1:通过session进行验证

session 称为"会话",session 对象存储特定用户会话所需的属性及配置信息。简言之,session 就是服务器为了储存用户信息而创建的一个验证手段。用户在登录了一个系统后,服务器会将登录信息储存在一个 session 中,产生 session ID,客户端会保存该 ID;当这个用户再登录其他系统时,服务器会自动复制上一个模块的 session 该服务器的 session 中,以获取用户登录信息,实现用户只登录一次,就可以登录其他系统。在用户退出登录时,服务器会自动删除 session。

整个过程均在服务器端完成,用户实际使用时没有感知。

方式2:通过cookie进行验证

cookie 是某些网站为了辨别用户身份,由服务端生成,发给客户端暂时或永久保存的信息。简言之,cookie 就是一种存储用户数据的媒介。举例来说,当我们打开一个网站,比如新浪、CSDN、知乎时,输入用户名和密码登录后系统会弹出是否保存 cookie,如果我们选择保存,在下一次登录时,就不需要再次输入用户名和密码,而是默认登录成功,直接进入页面。

方式3:通过token进行验证

token 在身份认证中是令牌的意思,在词法分析中是标记的意思。一般作为邀请、登录系统使用。简言之,token 就是一种凭证,用户在登录注册时需要获取凭证,在经过验证后,方可登录相关被授权的应用。

用户在首次登录系统时输入账号和密码,服务器会收到登录请求,然后验证是否正确;

服务器会根据用户信息,如用户 ID、用户名、秘钥、过期时间等信息生成一个 token 签名,然后发给用户;

用户验证成功后,返回 token;

前端服务器收到 token 后,存储到 cookie 或 Local Storage 里;当用户再次登录时,会被服务器验证 token;

服务器收到用户登录请求后,对 token 签名进行比对:如果 token 验证正确,用户登录成功;如果 token 验证不正确,用户登录失败,跳转到登录页。

区别

在 Authing 中,无需手动编写操作 session、cookie 或是 token,控制台中可以一键体验单点登录功能,并且支持自建与集成第三方等多种方式,还可以通过 SDK 接入并自定义自己的应用与登录方式。

同域名下的单点登录

cookiedomain属性设置为当前域的父域,并且父域的cookie会被子域所共享。path属性默认为web应用的上下文路径。

利用cookie的这个特点,没错,我们只需要将cookiedomain属性设置为父域的域名(主域名),同时将cookiepath属性设置为根路径,将Session ID(或 Token)保存到父域中。这样所有的子域应用中就都恶意访问到这个cookie

不过这要求应用系统的域名需建立在一个共同的主域名之下,如tieba.baidu.commap.baidu.com,它们都建立在baidu.com这个主域名之下,那么它们就可以通过这种方式来实现单点登录。

不同域名下的单点登录(1)

如果是不同域的情况下,cookie是不共享的,这里我们可以部署一个认证中心,用于专门处理登录请求的独立Web服务。

用户统一在认证中心登录,登录成功后,认证中心记录用户的登录状态,并将token写入cookie(注意这个cookie是认证中心的,应用系统是访问不到的)

应用系统检查当前请求有没有token,如果没有,说明用户在当前系统中尚未登录,那么就将页面跳转至认证中心。

由于这个操作会将认证中心的cookie自动带过去,因此,认证中心能够根据cookie知道用户是否已经登录过了。

  • 如果认证中心发现用户尚未登录,则返回登录页面,等待用户登录。
  • 如果发现用户已经登录过了,就不会让用户再次登录了,而是会跳转回目标URL,并在跳转前生成一个token,拼接在目标URL的后面,回传给目标应用系统。

应用系统拿到token之后,还需要像认证中心确认下token的合法性,防止用户伪造。确认无误后,应用系统记录用户的登录状态,并将token写入cookie,然后给本次访问放行。(注意这个cookie是当前应用系统的)当用户再次访问当前应用系统时,就会自动带上这个token,应用此种实现方式相对复杂,支持跨域,扩展性好,是单点登录的标准做法。

不同域名下的单点登录(2)

可以将Session ID(或 Token)保存到浏览器的LocalStorage中,让前端在每次向后端发送请求时,主动将LocalStorage的数据传递给服务端。这些都是由前端来控制的,后端需要做的仅仅是在用户登录成功后,将Session ID(或 Token)放在响应体中传递给前端。

单点登录完全可以在前端实现。前端拿到Session ID(或 Token)后,除了将它写入自己的LocalStorage中之外,还可以通过特殊手段将它写入多个其他领域下的LocalStorage中。

关键代码如下:

js 复制代码
// 获取token
let token = result.data.token;

// 动态创建一个不可见的iframe,在iframe中加载一个跨域HTML
let iframe = document.createElement("iframe")
iframe.src = "http://app1.com/local.html"
document.body.append(iframe);

// 使用postMessage() 方法将token传递给iframe
setTimeout(function(){
    iframe.contentWindow.postMessage(token,"http://app1.com")
},4000)

setTimeout(function(){
    iframe.remove()
},6000)


// 在这个iframe所加载的HTML终绑定一个事件监听器,当事件被触发时,把接收到的token数据写入localStorage
window.addEventListener('message',function(event){
    localStorage.setItem('token',event.data)
},false)

前端通过iframe + postMessage()方式,将同一份token写入到多个域下的LocalStorage中,前端每次向后端发送请求之前,都会主动从LocalStorage中读取token,并在请求中携带,这样就实现了同一份token被多个域所共享。

此种方式完全由前端控制,几乎不需要后端参与,同样支持跨域。

可能会用到的算法

通过key获取当前浏览器地址URL上的value

js 复制代码
function getUrlValue(name) {
  let reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)')
  let r = window.location.search.substr(1).match(reg)
  if (r != null) return unescape(r[2])
  return null
}

eg:

js 复制代码
// url :https://www.baidu.com?a=1&b=2

getUrlValue(a)  // 1
getUrlValue(b)  // 2
相关推荐
stayong13 分钟前
市面主流跨端开发框架对比
前端
庞囧26 分钟前
大白话讲 React 原理:Scheduler 任务调度器
前端
东华帝君39 分钟前
react 虚拟滚动列表的实现 —— 动态高度
前端
CptW41 分钟前
手撕 Promise 一文搞定
前端·面试
温宇飞42 分钟前
Web 异步编程
前端
腹黑天蝎座42 分钟前
浅谈React19的破坏性更新
前端·react.js
东华帝君42 分钟前
react组件常见的性能优化
前端
第七种黄昏42 分钟前
【前端高频面试题】深入浏览器渲染原理:从输入 URL 到页面绘制的完整流程解析
前端·面试·职场和发展
angelQ42 分钟前
前端fetch手动解析SSE消息体,字符串双引号去除不掉的问题定位
前端·javascript
Huangyi43 分钟前
第一节:Flow的基础知识
android·前端·kotlin