用 Authing 10分鐘實現單點登陸(SSO)

單點登陸(Single Sign On),簡稱爲SSO,是目前比較流行的企業業務整合的解決方案之一。
SSO的定義是在多個應用系統中,用戶只須要登陸一次就能夠訪問全部相互信任的應用系統。javascript

實現單點登陸

開始以前

若是你不瞭解用戶池、單點登陸和認證受權,建議先閱讀基礎概念html

預備知識

  1. 基本的 HTML 和 CSS 知識
  2. 中級 JavaScript 技能

所需工具

  1. 你喜歡的文本編輯器
  2. 能夠在本地運行的 Web 服務器(好比:npm install http-server -g

註冊一個 Authing 帳號

若是你尚未帳號,請點擊這裏註冊 Authing 帳號,註冊完成後請進入控制檯並建立一個用戶池。java

创建用户池

选择应用类型

建立一個 OIDC 應用

第三方登陸 -> OIDC 應用選項卡,點擊藍色的「建立 OIDC 應用」按鈕。git

创建 ODC 应用

填上你的應用名,指定此 OIDC 應用的二級域名(認證地址),回調地址,其餘參數保留默認便可。點擊「肯定」。 github

配置 OIDC 应用

參數解釋web

認證地址,一個 authing.cn 的二級域名,用戶將在此網址進行登陸。算法

回調 URL,OIDC 登陸成功後,回調到開發者本身業務的地址。本教程爲演示,填寫的地址是 http://localhost:8080,實際場景下要填寫本身的業務地址。npm

在應用列表中點擊剛建立好的應用,記錄下 AppID,二級域名,供之後使用。json

使用 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 端口已被佔用,應用可能會運行在 808一、8082 等後續端口。
{% endhint %}

運行效果

最初,咱們沒有登陸,所以,點擊 trackSession 按鈕獲取到的登陸狀態爲空。

如今咱們點擊 login 按鈕,會跳轉到 OIDC 應用的用戶認證頁面,輸入用戶名密碼進行登陸。

瀏覽器被重定向到咱們以前設置的回調連接,記下 code 參數,用於後面換取用戶信息。

點擊 trackSession 按鈕,此時可以獲取到該用戶的登陸狀態,包括用戶 ID,應用 ID,應用類型。

點擊 logout 按鈕,輸出單點登出成功。

此時咱們再點擊 trackSession 按鈕,可見登陸狀態爲空,說明用戶已經單點登出了。

獲取用戶信息

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

向如下地址發送 POST 請求:

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

body 參數

參數名 意義
client_id OIDC 應用的 app_id
redirect_uri 在控制檯配置的 OIDC 回調 url 其中的一個值
scope 須要請求的權限,若是須要獲取 email 和手機號須要有 phone email,若是須要 refresh_token 須要包含 offline_access 參考 scope 表格
response_type OIDC 模式,能夠爲 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 會幫助你認證他們的身份和返回必要的用戶信息到你的應用中。

<div align=center>Authing 在應用交互中的位置</div>

相關文章
相關標籤/搜索