跳转至

给任意网页添加身份验证

在本指南中,您将使用 ExpressJS 搭建一个简单的网站服务器来托管 SPA 应用。我们还会用它来提供 HTML 页面及其所需的各种资源,如 JavaScript、CSS 等。您也可以在 GitHub 仓库中查看完整源代码。

准备工作

  • 开始之前,请确保您的系统上已安装 Node.js。如果尚未安装,请从官方网站下载并安装。
  • Authany 账号: 您需要一个 Authany 账号才能跟随本指南操作。如果还没有账号,可以在 Authany 网站上免费创建。
  • 已注册的应用: 您需要在 Authany 中注册一个应用类型(单页应用)。请按照设置应用指南操作,并跳过安装 Authany Web SDK部分。您将通过 IIFE(立即调用函数表达式)打包文件从 Authany 的 CDN 获取 Authany Web SDK,并在 HTML 中直接引用该脚本。

创建基础 Web 服务器

首先在电脑上新建一个文件夹,用来存放应用的源代码(在示例中,我们将其命名为 authgear-spa-js-login)。然后运行以下命令初始化一个新的 NPM 项目:

npm init -y

接下来,安装两个必需的包:

npm install express

同时安装 nodemon,这样在开发模式下代码发生变化时,服务器就能自动重启:

npm install -D nodemon

接下来,打开 package.json 文件,编辑 scripts 字段,加入 start 和 dev 命令,如下所示:

{
  // ...
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js"
  },
  // ...
}

现在您可以用两种模式运行应用:生产模式和开发模式。

例如,npm run dev 会使用 nodemon 运行应用,并在您修改文件时监听变化。

创建 server.js

在项目根目录下创建一个新文件 server.js,并写入以下代码:

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

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

// Endpoint to serve the configuration file
app.get("/authgear_config.json", (req, res) => {
  res.sendFile(join(__dirname, "authgear_config.json"));
});

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

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

创建基础 HTML 页面

在项目根目录下创建一个 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="js/app.js"></script>
    <script src="<https://unpkg.com/@authgear/web@2.2.0/dist/authgear-web.iife.js>"></script>
  </body>
</html>

我们不使用像 Webpack 这样的打包工具,而是通过 IIFE(立即调用函数表达式)打包文件从 Authany 的 CDN 获取 Authany Web SDK。我们可以在 HTML 中直接引用该脚本:

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

您也可以将 Authany Web SDK 作为应用的依赖包安装,这在构建 React 或 React Native 应用时会很有用。了解如何安装该包。

创建 main.css 文件

在项目根目录下创建一个名为 public 的新文件夹,再在 public 文件夹内创建一个名为 css 的文件夹。在其中新建一个名为 main.css 的文件。它用来根据用户是否已通过身份验证,决定主页面上登录和登出按钮元素的显示或隐藏。

打开新建的 public/css/main.css 文件,添加以下 CSS:

.hidden {
    display: none;
}

label {
    margin-bottom: 10px;
    display: block;
}

创建好 HTML 文件并应用 CSS 样式后,运行 npm run dev 并访问 http://localhost:3000,看看页面现在的效果。

创建 app.js 文件

为了给页面添加一些交互,我们在 public 文件夹中新建一个名为 js 的目录,并在其中添加一个新文件 app.js。复制粘贴以下 JS 代码,它通过 fetchAuthConfig 函数从端点读取 authgear_config.json 文件中 Authany 应用的专属值(endpoint 和 clientId)。同时,它还会配置一个新的 Authany 客户端,并定义登录和登出逻辑:

let authgearClient = null;

const fetchAuthConfig = () => fetch("/authgear_config.json");

const configureClient = async () => {
    const response = await fetchAuthConfig();
    const config = await response.json();
    authgearClient = window.authgear.default;

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

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

const logout = () => {
    authgearClient
    .logout({
      redirectURI: window.location.origin,
    })
    .then(
      () => {
        console.log("Logged out successfully");
      },
      (err) => {
        console.log("Failed to logout");
      }
    );
};

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

    const query = window.location.search;
    if (query.includes("code=")) {

        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;
};

理解整体流程

让我们分解上一节中的 app.js 代码,了解 Authany 是如何实现身份验证的:

配置 Authany 客户端

fetchAuthConfig:首先,该函数会向我们在 server.js 中暴露的 /authgear_config.json 端点发起请求,从 authgear_config.json 文件中获取 Authany 应用的配置值。

configureClient:从 authgear_config.json 文件获取到 Authany 客户端的配置信息后,我们用这些设置来配置 Authany 客户端。它还会在控制台输出一条消息,说明配置是否成功。

登录流程

login:该函数由之前在 HTML 页面上定义的登录按钮调用。它通过调用 Authany 的 authgearClient.startAuthentication 函数来执行登录操作,将用户重定向到 Authany 登录页面。用户登录成功后,会被重定向回我们在 redirectURI 中设置的同一个页面。运行项目并点击登录按钮,您应该会跳转到为您的应用配置的 Authany 登录页面。

接下来创建一个新用户,或使用邮箱登录(我们在第一部分中指定了无密码邮箱登录方式)。当您尝试用邮箱登录时,系统会向您的邮箱发送一个魔法链接,用于确认登录操作。

身份验证成功后,您将被重定向回之前所在的页面。

登出流程

logout:该函数会将用户登出,并重定向回原始页面(http://localhost:3000)。它使用 Authany 的 logout 函数,并在控制台输出一条消息说明操作结果。

更新界面

window.onload:这是一个在页面加载时运行的函数。它会配置 Authany 客户端并更新界面。如果页面的 URL 中包含 “code=”,就说明用户已通过身份验证(code 是从 Authany 服务器接收到的查询参数),此时它会再次更新界面,并从 URL 中移除 “code=”。

评估身份验证状态

updateUI:该函数会根据用户是否已通过身份验证,更新登录和登出按钮的状态。在 Authany 中,您可以通过 sessionState 属性来检查用户是否已登录。如果用户已通过身份验证,我们会禁用登录按钮并启用登出按钮;如果用户未通过身份验证,则相反。