跳转至

JavaScript (Web)

本指南将介绍如何使用 Token 方式(Token Approach)将 Authany 集成到您的网站。在 Token 方式中,用户身份验证成功后,Authany 服务器会向您的 SPA 应用返回访问令牌和刷新令牌。

之后,您的应用可以在后续的 HTTP 请求中携带访问令牌,以访问受保护的资源。

按照本指南,您可以在 🕐 10 分钟内为任意 Web 应用接入 Authany SDK。

说明

本教程演示应用的完整代码,请在 这个 GitHub 仓库 中查看并克隆。

本指南使用 Authany Web SDK 将 Authany 集成到 SPA Web 应用中。支持的浏览器包括:

  • 最新 2 个 Firefox 主要版本
  • 最新 2 个 Chrome 主要版本
  • 最新 2 个 Edge 主要版本
  • 最新 3 个 Safari 主要版本

在 Authany 中设置应用

前往 https://manage.authany.com/ 注册 Authany 管理台账号,或者使用您自建部署的 Authany。

在项目列表中,新建一个项目或选择一个已有项目。接下来,我们需要在该项目中创建一个应用。

步骤 1:在管理台中创建应用

在左侧菜单栏中进入应用。

在顶部工具栏中点击 ⊕Add Application。

输入应用名称,并选择应用类型为单页应用(Single Page Application)。点击保存按钮继续。

在 Authany 管理台创建 SPA 应用

下一屏会显示不同框架的教程列表,点击下一步跳转到客户端应用配置页面。

步骤 2:配置应用

首先,确定用户在 Authany 完成身份验证后,网站中要跳转到的路径。

要离线运行本教程中的演示应用,请滚动到客户端应用页面的 URI 部分,添加以下 URI:

在授权重定向 URI下添加 http://localhost:3000/

说明

请注意,上述 URL 末尾的 "/" 必须保留。

编辑应用

点击保存按钮以保存更改。

使用 JavaScript 将 Authany 添加到任意网页

在本节中,我们将创建一个简单的网页,并使用 Authany Web JavaScript SDK 为其添加用户身份验证功能。

步骤 1:创建一个基础单页 Web 应用

在本指南中,我们将创建一个只有一个页面的基础 Web 应用。请按以下步骤搭建该应用。首先,在您的计算机上为项目新建一个目录。您可以在终端中使用以下命令完成:

mkdir my-webapp
cd my-webapp

步骤 2:创建 Web 服务器

我们将在 Web 项目目录中创建一个 Express.js 服务器,以便通过 http://localhost:3000 在浏览器中访问 HTML 页面。请在 Web 项目目录的根目录下运行以下命令安装 Express。

首先,在项目目录中生成一个 package.json 文件:

npm init -y

安装 Express npm 包:

npm install express

安装 Nodemon(用于为 JavaScript 开发添加热重载):

npm install -D nodemon

现在在项目根目录下创建一个 server.js 文件,并将以下代码添加到 server.js 中:

const express = require("express");
const { join } = require("path");
const path = require("path");
const app = express();

// Serve static assets from the /public folder
app.use(express.static(join(__dirname, "public")));

// Serve the index page for all other requests
app.get(/.*/, (req, res) => {
  res.sendFile(path.join(__dirname, "index.html"));
});

// Listen on port 3000
app.listen(3000, () => console.log("Application running on port 3000"));

接下来,打开项目目录中的 package.json,在 script 部分添加以下几行:

"start": "node server.js",
"dev": "nodemon server.js"

说明

请注意,您也可以使用自己偏好的工具/环境来提供 HTML 文件,从而跳过创建 Express 服务器这一步。

步骤 3:创建网页

在项目目录的根目录下创建一个名为 index.html 的新文件,并添加以下代码:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Authgear SPA SDK Sample</title>
    <link rel="stylesheet" type="text/css" href="/css/main.css" />
  </head>

  <body>
    <h2>SPA Authentication Sample</h2>
    <p>Welcome to our page!</p>
    <button id="btn-login" disabled="true" onclick="login()">Log in</button>
    <button id="btn-logout" disabled="true" onclick="logout()">Log out</button>
  </body>
</html>

index.html 的内容是一个简单的网页,包含一些文本、一个登录按钮和一个登出按钮。在后续步骤中,我们将为这两个按钮实现 onclick 事件,分别调用 Authany Web JavaScript SDK 中对应的函数。

步骤 4:安装 Authany Web JavaScript SDK

CDN

Web JS SDK 已发布到 CDN 上,您可以使用以下 script 标签将其引入任意网页:

<script src="https://unpkg.com/@authgear/web@2.2.0/dist/authgear-web.iife.js"></script>

Web JS SDK 同时也发布为 npm 包,可以使用以下任一命令安装:

NPM

npm install --save --save-exact @authgear/web

Yarn

yarn add @authgear/web --exact

当您使用 Vite、Webpack 等构建工具,或使用 React、Vue、Angular 等框架进行开发时,建议使用 npm 包将 Authany 添加到您的 Web 应用中。

要将 Authany SDK 这类 JavaScript 库添加到普通的单页应用(一个基础的 .html 文件页面)中,最简单的方式是使用 CDN。因此,本教程的演示应用将使用 CDN 方式添加 Authany Web JavaScript SDK。

要安装 Authany SDK,请在 index.html 中 </body> 前新增一行,加入 Authany SDK CDN 的 <script> 标签。此时您的 index.html 应如下所示:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Authgear SPA SDK Sample</title>
    <link rel="stylesheet" type="text/css" href="/css/main.css" />
  </head>

  <body>
    <h2>SPA Authentication Sample</h2>
    <p>Welcome to our page!</p>
    <button id="btn-login" disabled="true" onclick="login()">Log in</button>
    <button id="btn-logout" disabled="true" onclick="logout()">Log out</button>
    <script src="https://unpkg.com/@authgear/web@2.2.0/dist/authgear-web.iife.js"></script>
  </body>
</html>

至此,我们已经把 Authany SDK 添加到了一个基础 HTML 页面中,可以开始调用它的函数了。

检查点

此时,您的项目文件夹结构应如下所示:

my-webapp
├── index.html
├── server.js
└── package.json

要测试目前的进度,请保存文件后运行 npm run dev 命令,然后在您常用的浏览器中打开 localhost:3000,您应该会看到如下页面:

SPA 演示 Web 应用页面

步骤 5:初始化 Authany SDK

在项目目录根目录下新建一个 public/js 目录。

在 public/js 目录中创建一个名为 app.js 的新文件。将以下内容添加到 app.js 中:

let authgearClient = null;

const configureClient = async () => {
    authgearClient = window.authgear.default;

    await authgearClient.configure({
        endpoint: "<YOUR_AUTHGEAR_PROJECT_DOMAIN>",
        clientID: "<YOUR_AUTHGEAR_APP_CLIENT_ID>",
        sessionType: "refresh_token",
    }).then(
        () => {
            console.log("Authgear client successfully configured!");
        },
        (err) => {
            console.log("Failed to configure Authgear");
        }
    );
};

window.onload = async () => {
    await configureClient();
}

在 app.js 中,configureClient() 函数获取 Authany Web SDK 的实例(authgearClient),然后调用该 SDK 的 configure() 函数来初始化 Authany。

您可以在 Authany 客户端应用配置页面中找到 clientID 和 endpoint 的值。

最后,在 index.html 中 Authany CDN <script> 标签所在行的上方,使用 <script src="js/app.js"></script> 引入 app.js,如下所示:

<body>
  <h2>SPA Authentication Sample</h2>
  <p>Welcome to our page!</p>
  <button id="btn-login" disabled="true" onclick="login()">Log in</button>
  <button id="btn-logout" disabled="true" onclick="logout()">Log out</button>
  <script src="js/app.js"></script>
  <script src="https://unpkg.com/@authgear/web@2.2.0/dist/authgear-web.iife.js"></script>
</body>

步骤 6:启动身份验证流程

当用户在您的网站上点击登录/注册时,需要发起一次 start authorization 调用,将用户跳转到登录/注册页面(AuthUI)。

在本步骤中,我们将实现 login() 函数,当用户点击登录按钮时会调用该函数。

在 configureClient() 函数声明之后,向 app.js 添加以下代码:

const login = async () => {
    await authgearClient
        .startAuthentication({
            redirectURI: "http://localhost:3000/",
            prompt: "login",
        })
        .then(
            () => {
                console.log("Logged in!");
            },
            (err) => {
                console.log("Log in failed", err);
            }
        );
};

说明

请确保您已在管理台中为 Authany 客户端应用添加 http://localhost:3000/ 作为授权重定向 URI。请注意 URL 末尾的 "/" 是必需的。

步骤 7:在 redirectURI 中处理身份验证结果

用户在登录页面完成身份验证后,会被跳转到带有 code 查询参数的 redirectURI。在应用的 redirectURI 中,需要发起一次 finish authorization 调用来处理身份验证结果,该调用会尝试用 code 换取访问令牌和用户信息。

授权成功后,应用即可显示用户信息并访问受保护的资源。

为处理身份验证后的跳转,当当前页面的 URL 中存在 code 参数时,我们会调用 Authany SDK 的 finishAuthentication() 函数。为此,请将 app.js 中的 window.onload 回调更新为如下内容:

window.onload = async () => {
    await configureClient();
    updateUI();

    const query = window.location.search;
    if (query.includes("code=")) {
        await authgearClient.finishAuthentication();
        updateUI();
        window.history.replaceState({}, document.title, "/");
    }
}

updateUI() 函数会在用户登录状态发生变化时更新网页的状态。请在 app.js 末尾添加以下代码来实现 updateUI:

const updateUI = async () => {
    const isAuthenticated = authgearClient.sessionState === "AUTHENTICATED";

    document.getElementById("btn-logout").disabled = !isAuthenticated;
    document.getElementById("btn-login").disabled = isAuthenticated;
};

完成本步骤后,app.js 的完整内容应如下所示:

let authgearClient = null;

const configureClient = async () => {
    authgearClient = window.authgear.default;

    await authgearClient.configure({
        endpoint: "<YOUR_AUTHGEAR_PROJECT_DOMAIN>",
        clientID: "<YOUR_AUTHGEAR_CLIENT_APP_ID>",
        sessionType: "refresh_token",
    }).then(
        () => {
            console.log("Authgear client successfully configured!");
        },
        (err) => {
            console.log("Failed to configure Authgear");
        }
    );
};

const login = async () => {
    await authgearClient
        .startAuthentication({
            redirectURI: "http://localhost:3000/",
            prompt: "login",
        })
        .then(
            () => {
                console.log("Logged in!");
            },
            (err) => {
                console.log("Log in failed", err);
            }
        );
};

window.onload = async () => {
    await configureClient();
    updateUI();

    const query = window.location.search;
    if (query.includes("code=")) {
        await authgearClient.finishAuthentication();
        updateUI();
        window.history.replaceState({}, document.title, "/");
    }
}

const updateUI = async () => {
    const isAuthenticated = authgearClient.sessionState === "AUTHENTICATED";

    document.getElementById("btn-logout").disabled = !isAuthenticated;
    document.getElementById("btn-login").disabled = isAuthenticated;
};

检查点

此时,您的文件结构应如下所示:

my-webapp
├── index.html
├── server.js
├── public/js
│   └── app.js
└── package.json

保存代码中的所有更改,然后在浏览器中重新运行您的应用。这次,点击登录按钮应会将您跳转到 Authany 项目的用户登录页面(AuthUI)。

步骤 8:打开用户设置页面

要为您的应用添加一个用户设置按钮,请在 index.html 中登出按钮下方添加以下标签:

<button id="btn-settings" disabled="true" onclick="openUserSettings()">User Settings</button>

接下来,在 logout() 函数下方,将以下代码添加到 app.js 中:

const openUserSettings = () => {
    authgearClient.open("/settings");
}

最后,在 updateUI() 函数末尾添加以下一行,使用户登录后能够显示用户设置按钮:

document.getElementById("btn-settings").disabled = !isAuthenticated;

保存工作并重新运行您的应用。点击用户设置按钮后,您的 Web 应用应会打开预置的用户设置页面。

步骤 9:其他操作

获取登录状态

启动应用时,您可能需要判断用户是否已登录(例如,未登录用户跳转到登录页面)。sessionState 反映的是 SDK 本地状态中的用户登录状态,这意味着即使 sessionState 为 AUTHENTICATED,如果会话已在远端被撤销,该会话仍可能是无效的。初始化 Authany SDK 后,请在合适的时机调用 fetchUserInfo 来更新 sessionState。

// After authgearClient.configure, it only reflect SDK local state.
// value can be NO_SESSION or AUTHENTICATED
let sessionState = authgearClient.sessionState;

if (sessionState === "AUTHENTICATED") {
    authgearClient
        .fetchUserInfo()
        .then((userInfo) => {
            // sessionState is now up to date
        })
        .catch((e) => {
            // sessionState is now up to date
            // it will change to NO_SESSION if the session is invalid
        });
}

sessionState 的取值可以是 UNKNOWN、NO_SESSION 或 AUTHENTICATED。初始时 sessionState 为 UNKNOWN。调用 authgearClient.configure 后,如果找到之前的会话,会话状态会变为 AUTHENTICATED;如果没有找到,则变为 NO_SESSION。

获取用户信息

在某些情况下,您可能需要通过 SDK 获取当前用户信息(例如在界面中显示邮箱地址)。使用 fetchUserInfo 函数即可获取用户信息。

authgearClient.fetchUserInfo();

更多用户信息相关的示例,请参见此处。

登出用户

使用 logout 函数登出用户。用户会被跳转到您的 Authany 端点以登出会话,您应提供 redirectURI,以便用户返回您的应用。

authgearClient
  .logout({
    // user will navigate to the redirectURI after logged out
    // make sure it is in the "Post Logout Redirect URIs" in the application portal
    redirectURI: "https://yourdomain.com",
  })
  .then(
    () => {
      // logged out successfully
    },
    (err) => {
      // failed to logout
    }
  );

调用 API

用户登录后,您就可以按以下方式向后端 API 发起经过身份验证的请求。

基于 Token 的身份验证

在向应用服务器发起的 HTTP 请求中携带访问令牌有两种方式。

方式 1:使用 Authany SDK 提供的 fetch 函数

Authany SDK 提供了 fetch 函数,供您调用应用服务器。该 fetch 函数会自动在应用请求中携带 Authorization 头,并自动处理访问令牌的刷新。authgearClient.fetch 实现了 fetch 规范。

authgearClient
    .fetch("YOUR_SERVER_URL")
    .then(response => response.json())
    .then(data => console.log(data));

方式 2:将访问令牌添加到 HTTP 请求头

您可以通过 authgearClient.accessToken 获取访问令牌。每次使用访问令牌前,请调用 refreshAccessTokenIfNeeded,该函数会进行检查,只有在令牌过期时才会发起网络请求刷新令牌。请将访问令牌放入应用请求的 Authorization 头中。

authgearClient
    .refreshAccessTokenIfNeeded()
    .then(() => {
        // access token is ready to use
        // accessToken can be string or undefined
        // it will be empty if user is not logged in or session is invalid
        const accessToken = authgearClient.accessToken;

        // include Authorization header in your application request
        const headers = {
            Authorization: `Bearer ${accessToken}`
        };
    });

后续步骤

为保护应用服务器免受未授权访问,您需要将 Authany 集成到后端。

后端/API 集成

JavaScript SDK 参考

有关 JavaScript Web SDK 的详细文档,请访问 @authgear/web Reference