用 Authing 10分钟实现单点登录(SSO)

单点登录(Single Sign On),简称为SSO,是目前比较流行的企业业务整合的解决方案之一。
SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

实现单点登录

开始之前

如果你不了解用户池、单点登录和认证授权,建议先阅读基础概念

预备知识

  1. 基本的 HTML 和 CSS 知识
  2. 中级 JavaScript 技能

所需工具

  1. 你喜欢的文本编辑器
  2. 可以在本地运行的 Web 服务器(比如:npm install http-server -g

注册一个 Authing 账号

如果你还没有账号,请点击这里注册 Authing 账号,注册完成后请进入控制台并创建一个用户池。

《用 Authing 10分钟实现单点登录(SSO)》

《用 Authing 10分钟实现单点登录(SSO)》

创建一个 OIDC 应用

第三方登录 -> OIDC 应用选项卡,点击蓝色的「创建 OIDC 应用」按钮。

《用 Authing 10分钟实现单点登录(SSO)》

填上你的应用名,指定此 OIDC 应用的二级域名(认证地址),回调地址,其他参数保留默认即可。点击「确定」。

《用 Authing 10分钟实现单点登录(SSO)》

参数解释

认证地址,一个 authing.cn 的二级域名,用户将在此网址进行登录。

回调 URL,OIDC 登录成功后,回调到开发者自己业务的地址。本教程为演示,填写的地址是 http://localhost:8080,实际场景下要填写自己的业务地址。

在应用列表中点击刚创建好的应用,记录下 AppID,二级域名,供以后使用。

使用 AuthingSSO SDK 集成单点登录

创建一个空白的 HTML 文档用来编写 Authing 程序

本教程只是为了演示,因此我们没选择高级框架,这可以让我们专注于 Authing 本身。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Authing SSO Example</title>
  </head>
  <body></body>
</html>

添加三个按钮

增加三个按钮控件到 body 中,目的是为了演示如何使用 SDK 管理单点登录状态。

<button id="btn-login">login</button>
<button id="btn-track-session">trackSession</button>
<button id="btn-logout">logout</button>

引入 AuthingSSO 并初始化

从 CDN 加载 AuthingSSO 的 SDK。填入你的 OIDC 应用 ID 和 域名,进行初始化。

<script src="https://cdn.jsdelivr.net/npm/@authing/sso/dist/AuthingSSO.umd.min.js"></script>
<script>
  let auth = new AuthingSSO({
    appId: "YOUR_OIDC_APP_ID",
    appType: "oidc",
    appDomain: "OIDC_APP_DOMAIN.authing.cn"
  });
</script>

为按钮注册点击事件

达到的效果是:

  • 点击 login 按钮,浏览器会跳转到 OIDC 登录页面,与用户完成身份确认。
  • 点击 trackSession 按钮,会显示当前登录状态。
  • 点击 logout 按钮,进行单点登出。
let login = document.getElementById("btn-login");
let trackSession = document.getElementById("btn-track-session");
let logout = document.getElementById("btn-logout");
login.onclick = function() {
  auth.login();
};
trackSession.onclick = async function() {
  let res = await auth.trackSession();
  alert(JSON.stringify(res));
};
logout.onclick = async function() {
  let res = await auth.logout();
  alert(JSON.stringify(res));
};

完整代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Authing SSO Example</title>
  </head>
  <body>
    <button id="btn-login">login</button>
    <button id="btn-track-session">trackSession</button>
    <button id="btn-logout">logout</button>
    <script src="https://cdn.jsdelivr.net/npm/@authing/sso/dist/AuthingSSO.umd.min.js"></script>
    <script>
      let auth = new AuthingSSO({
        appId: "YOUR_OIDC_APP_ID",
        appType: "oidc",
        appDomain: "OIDC_APP_DOMAIN.authing.cn"
      });
      let login = document.getElementById("btn-login");
      let trackSession = document.getElementById("btn-track-session");
      let logout = document.getElementById("btn-logout");
      login.onclick = function() {
        auth.login();
      };
      trackSession.onclick = async function() {
        let res = await auth.trackSession();
        alert(JSON.stringify(res));
      };
      logout.onclick = async function() {
        let res = await auth.logout();
        alert(JSON.stringify(res));
      };
    </script>
  </body>
</html>

示例代码可从 Github 上找到,建议将 Github 上的代码下载运行。

运行方法

在终端中运行以下命令

$ git clone https://github.com/Authing/authing-sso-demo
$ cd authing-sso-demo
$ npm install -g http-server
$ http-server

之后在浏览器访问 http://localhost:8080

{% hint style=”warning” %}
如果本地 8080 端口已被占用,应用可能会运行在 8081、8082 等后续端口。
{% endhint %}

运行效果

最初,我们没有登录,因此,点击 trackSession 按钮获取到的登录状态为空。

《用 Authing 10分钟实现单点登录(SSO)》

现在我们点击 login 按钮,会跳转到 OIDC 应用的用户认证页面,输入用户名密码进行登录。

《用 Authing 10分钟实现单点登录(SSO)》

浏览器被重定向到我们之前设置的回调链接,记下 code 参数,用于后面换取用户信息。

点击 trackSession 按钮,此时能够获取到该用户的登录状态,包括用户 ID,应用 ID,应用类型。

《用 Authing 10分钟实现单点登录(SSO)》

点击 logout 按钮,输出单点登出成功。

《用 Authing 10分钟实现单点登录(SSO)》

此时我们再点击 trackSession 按钮,可见登录状态为空,说明用户已经单点登出了。

《用 Authing 10分钟实现单点登录(SSO)》

获取用户信息

使用 OIDC 流程中返回的 code 换取 access_token

向以下地址发送 POST 请求:

POST https://OIDC_APP_DOMAIN.authing.cn/oauth/oidc/token

body 参数

参数名意义
client_idOIDC 应用的 app_id
redirect_uri在控制台配置的 OIDC 回调 url 其中的一个值
scope需要请求的权限,如果需要获取 email 和手机号需要有 phone email,如果需要 refresh_token 需要包含 offline_access 参考 scope 表格
response_typeOIDC 模式,可以为 code, id_token, id_token token, code id_token, code token, code id_token token 参考 OIDC 规范
prompt可以为 none,login,consent 或 select_account,指定 AP 与 End-User 的交互方式,如需 refresh_token,必须为 consent 参考 OIDC 规范
state一个随机字符串,用于防范 CSRF 攻击,如果 response 中的 state 值和发送请求之前设置的 state 值不同,说明受到攻击
nonce一个随机字符串,用于防范 Replay 攻击

返回示例

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJqdGkiOiJ4R01uczd5cmNFckxiakNRVW9US1MiLCJzdWIiOiI1YzlmNzVjN2NjZjg3YjA1YTkyMWU5YjAiLCJpc3MiOiJodHRwczovL2F1dGhpbmcuY24iLCJpYXQiOjE1NTQ1Mzc4NjksImV4cCI6MTU1NDU0MTQ2OSwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBvZmZsaW5lX2FjY2VzcyBwaG9uZSBlbWFpbCIsImF1ZCI6IjVjYTc2NWUzOTMxOTRkNTg5MWRiMTkyNyJ9.wX05OAgYuXeYM7zCxhrkvTO_taqxrCTG_L2ImDmQjMml6E3GXjYA9EFK0NfWquUI2mdSMAqohX-ndffN0fa5cChdcMJEm3XS9tt6-_zzhoOojK-q9MHF7huZg4O1587xhSofxs-KS7BeYxEHKn_10tAkjEIo9QtYUE7zD7JXwGUsvfMMjOqEVW6KuY3ZOmIq_ncKlB4jvbdrduxy1pbky_kvzHWlE9El_N5qveQXyuvNZVMSIEpw8_y5iSxPxKfrVwGY7hBaF40Oph-d2PO7AzKvxEVMamzLvMGBMaRAP_WttBPAUSqTU5uMXwMafryhGdIcQVsDPcGNgMX6E1jzLA",
  "expires_in": 3600,
  "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJzdWIiOiI1YzlmNzVjN2NjZjg3YjA1YTkyMWU5YjAiLCJub25jZSI6IjIyMTIxIiwiYXRfaGFzaCI6Ik5kbW9iZVBZOEFFaWQ2T216MzIyOXciLCJzaWQiOiI1ODM2NzllNC1lYWM5LTRjNDEtOGQxMS1jZWFkMmE5OWQzZWIiLCJhdWQiOiI1Y2E3NjVlMzkzMTk0ZDU4OTFkYjE5MjciLCJleHAiOjE1NTQ1NDE0NjksImlhdCI6MTU1NDUzNzg2OSwiaXNzIjoiaHR0cHM6Ly9hdXRoaW5nLmNuIn0.IQi5FRHO756e_eAmdAs3OnFMU7QuP-XtrbwCZC1gJntevYJTltEg1CLkG7eVhdi_g5MJV1c0pNZ_xHmwS0R-E4lAXcc1QveYKptnMroKpBWs5mXwoOiqbrjKEmLMaPgRzCOdLiSdoZuQNw_z-gVhFiMNxI055TyFJdXTNtExt1O3KmwqanPNUi6XyW43bUl29v_kAvKgiOB28f3I0fB4EsiZjxp1uxHQBaDeBMSPaRVWQJcIjAJ9JLgkaDt1j7HZ2a1daWZ4HPzifDuDfi6_Ob1ZL40tWEC7xdxHlCEWJ4pUIsDjvScdQsez9aV_xMwumw3X4tgUIxFOCNVEvr73Fg",
  "refresh_token": "WPsGJbvpBjqXz6IJIr1UHKyrdVF",
  "scope": "openid profile offline_access phone email",
  "token_type": "Bearer"
}

验证 access_token 和 id_token 的合法性

OIDC 默认使用 OIDC 应用的 secret 对 token 进行验证(也就是在创建应用时默认选择 HS256 算法)。 如果你使用 javascript 那么可以使用 jsonwebtoken 进行验证:

const jwt = require('jsonwebtoken');
let decoded = jwt.verify(token, <appSecret>);

如果是其他语言,那么你在服务端需要用 app_secret 作为 HS256 签名参数来计算签名和 JWT 中的签名进行对比,伪代码如下:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  "1133fd20c14e4cc29b6ecb71fb8eb952"// app_secret
)

如果是 RS256 等非对称加密算法,需要使用公钥验证签名。Authing 将使用私钥进行签名,请使用 Authing 的公钥来验证签名:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxRijj2seoesv5K0Z+ymR
K7DSDPxdsM2sGQD2ZVhLjLsxZWJtXUXh7ERdUU6OT3BqYZZf7CLIhN6yyNtTOgfg
pLG9HVJd7ZSKzuy2dS7mo8jD8YRtptAJmNFqw6z8tQp5MNG1ZHqp9isKqJmx/CFY
kRdXBmjjj8PMVSP757pkC3jCq7fsi0drSSg4lIxrSsGzL0++Ra9Du71Qe/ODQKU0
brxaI1OKILtfcVPTHTaheV+0dw4eYkSDtyaLBG3jqsQbdncNg8PCEWchNzdO6aaj
Uq4wbOzy/Ctp399mz0SGKfuC5S8gqAFABFT3DH3UD21ZztQZwFEV2AlvF+bcGEst
cwIDAQAB
-----END PUBLIC KEY-----

使用 access_token 换取用户信息

开发者在自己的服务中可以使用 access_token 换取用户信息。根据 scope 的不同,这里的返回信息也会有所不同,字段符合 OIDC 规范,字段解释请参考用户信息字段含义。 请求链接:

GET https://users.authing.cn/oauth/oidc/user/userinfo?access_token=<access_token>

返回示例:

{
  "sub": "<用户在 Authing 的唯一标识>",
  "nickname": "Authing",
  "name": "张三",
  "locale": "en-US"
}

更多字段解释请参考用户信息字段含义

接下来你可能还需要

了解 OIDC 协议:

控制台是你管理所有 Authing 资源的地方,了解 Authing 控制台各模块包含的内容和你可以在控制台中做的事情:

了解 Authing 提供的多种部署模型,以帮助你选择该以怎样的形式部署 Authing:

什么是 Authing?

Authing 提供专业的身份认证和授权服务。
我们为开发者和企业提供用以保证应用程序安全所需的认证模块,这让开发人员无需成为安全专家。
你可以将任意平台的应用接入到 Authing(无论是新开发的应用还是老应用都可以),同时你还可以自定义应用程序的登录方式(如:邮箱/密码、短信/验证码、扫码登录等)。
你可以根据你使用的技术,来选择我们的 SDK 或调用相关 API 来接入你的应用。当用户发起授权请求时,Authing 会帮助你认证他们的身份和返回必要的用户信息到你的应用中。
《用 Authing 10分钟实现单点登录(SSO)》
<div align=center>Authing 在应用交互中的位置</div>

    原文作者:Authing
    原文地址: https://segmentfault.com/a/1190000020102115
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞