登录
注册
开源
企业版
高校版
搜索
帮助中心
使用条款
关于我们
开源
企业版
高校版
私有云
模力方舟
AI 队友
登录
注册
Gitee 2025年度个人数据报告已发布,快来看看你的成长👉
代码拉取完成,页面将自动刷新
捐赠
捐赠前请先登录
取消
前往登录
扫描微信二维码支付
取消
支付完成
支付提示
将跳转至支付宝完成支付
确定
取消
Watch
不关注
关注所有动态
仅关注版本发行动态
关注但不提醒动态
3
Star
47
Fork
21
DreamCoders
/
CoderGuide
代码
Issues
1169
Pull Requests
0
Wiki
统计
流水线
服务
JavaDoc
PHPDoc
质量分析
Jenkins for Gitee
腾讯云托管
腾讯云 Serverless
悬镜安全
阿里云 SAE
Codeblitz
SBOM
我知道了,不再自动展开
更新失败,请稍后重试!
移除标识
内容风险标识
本任务被
标识为内容中包含有代码安全 Bug 、隐私泄露等敏感信息,仓库外成员不可访问
什么是单点登录,以及如何进行实现?
待办的
#IAG9PD
陌生人
拥有者
创建于
2024-07-29 16:07
<h2>一、是什么</h2><p>单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一</p><p>SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统</p><p>SSO 一般都需要一个独立的认证中心(passport),子系统的登录均得通过<code>passport</code>,子系统本身将不参与登录操作</p><p>当一个系统成功登录以后,<code>passport</code>将会颁发一个令牌给各个子系统,子系统可以拿着令牌会获取各自的受保护资源,为了减少频繁认证,各个子系统在被<code>passport</code>授权以后,会建立一个局部会话,在一定时间内可以无需再次向<code>passport</code>发起认证</p><p><img src="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/2024062711164646713.png" alt="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/2024062711164646713.png" data-href="" style=""/></p><p>上图有四个系统,分别是<code>Application1</code>、<code>Application2</code>、<code>Application3</code>、和<code>SSO</code>,当<code>Application1</code>、<code>Application2</code>、<code>Application3</code>需要登录时,将跳到<code>SSO</code>系统,<code>SSO</code>系统完成登录,其他的应用系统也就随之登录了</p><h4>举个例子</h4><p>淘宝、天猫都属于阿里旗下,当用户登录淘宝后,再打开天猫,系统便自动帮用户登录了天猫,这种现象就属于单点登录</p><h2>二、如何实现</h2><h3>同域名下的单点登录</h3><p><code>cookie</code>的<code>domin</code>属性设置为当前域的父域,并且父域的<code>cookie</code>会被子域所共享。<code>path</code>属性默认为<code>web</code>应用的上下文路径</p><p>利用 <code>Cookie</code> 的这个特点,没错,我们只需要将<code>Cookie</code>的<code>domain</code>属性设置为父域的域名(主域名),同时将 <code>Cookie</code>的<code>path</code>属性设置为根路径,将 <code>Session ID</code>(或 <code>Token</code>)保存到父域中。这样所有的子域应用就都可以访问到这个<code>Cookie</code></p><p>不过这要求应用系统的域名需建立在一个共同的主域名之下,如 <code>tieba.baidu.com</code> 和 <code>map.baidu.com</code>,它们都建立在 <code>baidu.com</code>这个主域名之下,那么它们就可以通过这种方式来实现单点登录</p><h3>不同域名下的单点登录(一)</h3><p>如果是不同域的情况下,<code>Cookie</code>是不共享的,这里我们可以部署一个认证中心,用于专门处理登录请求的独立的 <code>Web</code>服务</p><p>用户统一在认证中心进行登录,登录成功后,认证中心记录用户的登录状态,并将 <code>token</code> 写入 <code>Cookie</code>(注意这个 <code>Cookie</code>是认证中心的,应用系统是访问不到的)</p><p>应用系统检查当前请求有没有 <code>Token</code>,如果没有,说明用户在当前系统中尚未登录,那么就将页面跳转至认证中心</p><p>由于这个操作会将认证中心的 <code>Cookie</code> 自动带过去,因此,认证中心能够根据 <code>Cookie</code> 知道用户是否已经登录过了</p><p>如果认证中心发现用户尚未登录,则返回登录页面,等待用户登录</p><p>如果发现用户已经登录过了,就不会让用户再次登录了,而是会跳转回目标 <code>URL</code>,并在跳转前生成一个 <code>Token</code>,拼接在目标<code>URL</code> 的后面,回传给目标应用系统</p><p>应用系统拿到 <code>Token</code>之后,还需要向认证中心确认下 <code>Token</code> 的合法性,防止用户伪造。确认无误后,应用系统记录用户的登录状态,并将 <code>Token</code>写入<code>Cookie</code>,然后给本次访问放行。(注意这个 <code>Cookie</code> 是当前应用系统的)当用户再次访问当前应用系统时,就会自动带上这个 <code>Token</code>,应用系统验证 Token 发现用户已登录,于是就不会有认证中心什么事了</p><p>此种实现方式相对复杂,支持跨域,扩展性好,是单点登录的标准做法</p><h3>不同域名下的单点登录(二)</h3><p>可以选择将 <code>Session ID</code> (或 <code>Token</code> )保存到浏览器的 <code>LocalStorage</code> 中,让前端在每次向后端发送请求时,主动将<code>LocalStorage</code>的数据传递给服务端</p><p>这些都是由前端来控制的,后端需要做的仅仅是在用户登录成功后,将 <code>Session ID</code>(或 <code>Token</code>)放在响应体中传递给前端</p><p>单点登录完全可以在前端实现。前端拿到 <code>Session ID</code>(或 <code>Token</code> )后,除了将它写入自己的 <code>LocalStorage</code> 中之外,还可以通过特殊手段将它写入多个其他域下的 <code>LocalStorage</code> 中</p><p>关键代码如下:</p><pre><code class="language-javascript">// 获取 token var token = result.data.token; // 动态创建一个不可见的iframe,在iframe中加载一个跨域HTML var iframe = document.createElement("iframe"); iframe.src = "http://app1.com/localstorage.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);</code></pre><p>前端通过 <code>iframe</code>+<code>postMessage()</code> 方式,将同一份 <code>Token</code> 写入到了多个域下的 <code>LocalStorage</code> 中,前端每次在向后端发送请求之前,都会主动从 <code>LocalStorage</code> 中读取<code>Token</code>并在请求中携带,这样就实现了同一份<code>Token</code> 被多个域所共享</p><p>此种实现方式完全由前端控制,几乎不需要后端参与,同样支持跨域</p><h2>三、流程</h2><p>单点登录的流程图如下所示:</p><p><img src="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/2024062711165993888.png" alt="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/2024062711165993888.png" data-href="" style=""/></p><ul><li>用户访问系统1的受保护资源,系统1发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数</li><li>sso认证中心发现用户未登录,将用户引导至登录页面</li><li>用户输入用户名密码提交登录申请</li><li>sso认证中心校验用户信息,创建用户与sso认证中心之间的会话,称为全局会话,同时创建授权令牌</li><li>sso认证中心带着令牌跳转会最初的请求地址(系统1)</li><li>系统1拿到令牌,去sso认证中心校验令牌是否有效</li><li>sso认证中心校验令牌,返回有效,注册系统1</li><li>系统1使用该令牌创建与用户的会话,称为局部会话,返回受保护资源</li><li>用户访问系统2的受保护资源</li><li>系统2发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数</li><li>sso认证中心发现用户已登录,跳转回系统2的地址,并附上令牌</li><li>系统2拿到令牌,去sso认证中心校验令牌是否有效</li><li>sso认证中心校验令牌,返回有效,注册系统2</li><li>系统2使用该令牌创建与用户的局部会话,返回受保护资源</li></ul><p>用户登录成功之后,会与<code>sso</code>认证中心及各个子系统建立会话,用户与<code>sso</code>认证中心建立的会话称为全局会话</p><p>用户与各个子系统建立的会话称为局部会话,局部会话建立之后,用户访问子系统受保护资源将不再通过<code>sso</code>认证中心</p><p>全局会话与局部会话有如下约束关系:</p><ul><li>局部会话存在,全局会话一定存在</li><li>全局会话存在,局部会话不一定存在</li><li>全局会话销毁,局部会话必须销毁</li></ul>
<h2>一、是什么</h2><p>单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一</p><p>SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统</p><p>SSO 一般都需要一个独立的认证中心(passport),子系统的登录均得通过<code>passport</code>,子系统本身将不参与登录操作</p><p>当一个系统成功登录以后,<code>passport</code>将会颁发一个令牌给各个子系统,子系统可以拿着令牌会获取各自的受保护资源,为了减少频繁认证,各个子系统在被<code>passport</code>授权以后,会建立一个局部会话,在一定时间内可以无需再次向<code>passport</code>发起认证</p><p><img src="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/2024062711164646713.png" alt="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/2024062711164646713.png" data-href="" style=""/></p><p>上图有四个系统,分别是<code>Application1</code>、<code>Application2</code>、<code>Application3</code>、和<code>SSO</code>,当<code>Application1</code>、<code>Application2</code>、<code>Application3</code>需要登录时,将跳到<code>SSO</code>系统,<code>SSO</code>系统完成登录,其他的应用系统也就随之登录了</p><h4>举个例子</h4><p>淘宝、天猫都属于阿里旗下,当用户登录淘宝后,再打开天猫,系统便自动帮用户登录了天猫,这种现象就属于单点登录</p><h2>二、如何实现</h2><h3>同域名下的单点登录</h3><p><code>cookie</code>的<code>domin</code>属性设置为当前域的父域,并且父域的<code>cookie</code>会被子域所共享。<code>path</code>属性默认为<code>web</code>应用的上下文路径</p><p>利用 <code>Cookie</code> 的这个特点,没错,我们只需要将<code>Cookie</code>的<code>domain</code>属性设置为父域的域名(主域名),同时将 <code>Cookie</code>的<code>path</code>属性设置为根路径,将 <code>Session ID</code>(或 <code>Token</code>)保存到父域中。这样所有的子域应用就都可以访问到这个<code>Cookie</code></p><p>不过这要求应用系统的域名需建立在一个共同的主域名之下,如 <code>tieba.baidu.com</code> 和 <code>map.baidu.com</code>,它们都建立在 <code>baidu.com</code>这个主域名之下,那么它们就可以通过这种方式来实现单点登录</p><h3>不同域名下的单点登录(一)</h3><p>如果是不同域的情况下,<code>Cookie</code>是不共享的,这里我们可以部署一个认证中心,用于专门处理登录请求的独立的 <code>Web</code>服务</p><p>用户统一在认证中心进行登录,登录成功后,认证中心记录用户的登录状态,并将 <code>token</code> 写入 <code>Cookie</code>(注意这个 <code>Cookie</code>是认证中心的,应用系统是访问不到的)</p><p>应用系统检查当前请求有没有 <code>Token</code>,如果没有,说明用户在当前系统中尚未登录,那么就将页面跳转至认证中心</p><p>由于这个操作会将认证中心的 <code>Cookie</code> 自动带过去,因此,认证中心能够根据 <code>Cookie</code> 知道用户是否已经登录过了</p><p>如果认证中心发现用户尚未登录,则返回登录页面,等待用户登录</p><p>如果发现用户已经登录过了,就不会让用户再次登录了,而是会跳转回目标 <code>URL</code>,并在跳转前生成一个 <code>Token</code>,拼接在目标<code>URL</code> 的后面,回传给目标应用系统</p><p>应用系统拿到 <code>Token</code>之后,还需要向认证中心确认下 <code>Token</code> 的合法性,防止用户伪造。确认无误后,应用系统记录用户的登录状态,并将 <code>Token</code>写入<code>Cookie</code>,然后给本次访问放行。(注意这个 <code>Cookie</code> 是当前应用系统的)当用户再次访问当前应用系统时,就会自动带上这个 <code>Token</code>,应用系统验证 Token 发现用户已登录,于是就不会有认证中心什么事了</p><p>此种实现方式相对复杂,支持跨域,扩展性好,是单点登录的标准做法</p><h3>不同域名下的单点登录(二)</h3><p>可以选择将 <code>Session ID</code> (或 <code>Token</code> )保存到浏览器的 <code>LocalStorage</code> 中,让前端在每次向后端发送请求时,主动将<code>LocalStorage</code>的数据传递给服务端</p><p>这些都是由前端来控制的,后端需要做的仅仅是在用户登录成功后,将 <code>Session ID</code>(或 <code>Token</code>)放在响应体中传递给前端</p><p>单点登录完全可以在前端实现。前端拿到 <code>Session ID</code>(或 <code>Token</code> )后,除了将它写入自己的 <code>LocalStorage</code> 中之外,还可以通过特殊手段将它写入多个其他域下的 <code>LocalStorage</code> 中</p><p>关键代码如下:</p><pre><code class="language-javascript">// 获取 token var token = result.data.token; // 动态创建一个不可见的iframe,在iframe中加载一个跨域HTML var iframe = document.createElement("iframe"); iframe.src = "http://app1.com/localstorage.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);</code></pre><p>前端通过 <code>iframe</code>+<code>postMessage()</code> 方式,将同一份 <code>Token</code> 写入到了多个域下的 <code>LocalStorage</code> 中,前端每次在向后端发送请求之前,都会主动从 <code>LocalStorage</code> 中读取<code>Token</code>并在请求中携带,这样就实现了同一份<code>Token</code> 被多个域所共享</p><p>此种实现方式完全由前端控制,几乎不需要后端参与,同样支持跨域</p><h2>三、流程</h2><p>单点登录的流程图如下所示:</p><p><img src="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/2024062711165993888.png" alt="https://jsd.onmicrosoft.cn/gh/iGaoWei/codercdn@master/question/20240627/2024062711165993888.png" data-href="" style=""/></p><ul><li>用户访问系统1的受保护资源,系统1发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数</li><li>sso认证中心发现用户未登录,将用户引导至登录页面</li><li>用户输入用户名密码提交登录申请</li><li>sso认证中心校验用户信息,创建用户与sso认证中心之间的会话,称为全局会话,同时创建授权令牌</li><li>sso认证中心带着令牌跳转会最初的请求地址(系统1)</li><li>系统1拿到令牌,去sso认证中心校验令牌是否有效</li><li>sso认证中心校验令牌,返回有效,注册系统1</li><li>系统1使用该令牌创建与用户的会话,称为局部会话,返回受保护资源</li><li>用户访问系统2的受保护资源</li><li>系统2发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数</li><li>sso认证中心发现用户已登录,跳转回系统2的地址,并附上令牌</li><li>系统2拿到令牌,去sso认证中心校验令牌是否有效</li><li>sso认证中心校验令牌,返回有效,注册系统2</li><li>系统2使用该令牌创建与用户的局部会话,返回受保护资源</li></ul><p>用户登录成功之后,会与<code>sso</code>认证中心及各个子系统建立会话,用户与<code>sso</code>认证中心建立的会话称为全局会话</p><p>用户与各个子系统建立的会话称为局部会话,局部会话建立之后,用户访问子系统受保护资源将不再通过<code>sso</code>认证中心</p><p>全局会话与局部会话有如下约束关系:</p><ul><li>局部会话存在,全局会话一定存在</li><li>全局会话存在,局部会话不一定存在</li><li>全局会话销毁,局部会话必须销毁</li></ul>
评论 (
0
)
登录
后才可以发表评论
状态
待办的
待办的
进行中
已完成
已关闭
负责人
未设置
标签
Html/JS/CSS
未设置
标签管理
里程碑
未关联里程碑
未关联里程碑
Pull Requests
未关联
未关联
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
未关联
未关联
master
开始日期   -   截止日期
-
置顶选项
不置顶
置顶等级:高
置顶等级:中
置顶等级:低
优先级
不指定
严重
主要
次要
不重要
参与者(1)
1
https://gitee.com/DreamCoders/CoderGuide.git
git@gitee.com:DreamCoders/CoderGuide.git
DreamCoders
CoderGuide
CoderGuide
点此查找更多帮助
搜索帮助
Git 命令在线学习
如何在 Gitee 导入 GitHub 仓库
Git 仓库基础操作
企业版和社区版功能对比
SSH 公钥设置
如何处理代码冲突
仓库体积过大,如何减小?
如何找回被删除的仓库数据
Gitee 产品配额说明
GitHub仓库快速导入Gitee及同步更新
什么是 Release(发行版)
将 PHP 项目自动发布到 packagist.org
评论
仓库举报
回到顶部
登录提示
该操作需登录 Gitee 帐号,请先登录后再操作。
立即登录
没有帐号,去注册