# 设置自定义后端

{% hint style="warning" %}
本指南将引导您设置文档的受保护登录屏幕。在阅读本指南之前，请先完成 [启用已验证访问](https://gitbook-v2-3sscp147r-gitbook.vercel.app/url/gitbook.com/docs/documentation/zh/fa-bu-wen-dang/authenticated-access/enabling-authenticated-access).
{% endhint %}

本指南将向您展示如何使用您自己的方式为 GitBook 文档站点设置受保护的登录屏幕，使用您自己的 **自定义** 身份验证后端。

{% hint style="info" %}
如果您正在使用我们支持的某个身份提供者或有一个 [OpenID Connect](https://auth0.com/docs/authenticate/protocols/openid-connect-protocol) (OIDC) 兼容的后端，请查看我们的集成指南以获得更简化的设置：\
\
[Auth0](https://gitbook-v2-3sscp147r-gitbook.vercel.app/url/gitbook.com/docs/documentation/zh/fa-bu-wen-dang/authenticated-access/setting-up-auth0) | [Azure AD](https://gitbook-v2-3sscp147r-gitbook.vercel.app/url/gitbook.com/docs/documentation/zh/fa-bu-wen-dang/authenticated-access/setting-up-azure-ad) | [Okta](https://gitbook-v2-3sscp147r-gitbook.vercel.app/url/gitbook.com/docs/documentation/zh/fa-bu-wen-dang/authenticated-access/setting-up-okta) | [AWS Cognito](https://gitbook-v2-3sscp147r-gitbook.vercel.app/url/gitbook.com/docs/documentation/zh/fa-bu-wen-dang/authenticated-access/setting-up-aws-cognito) | [OIDC](https://gitbook-v2-3sscp147r-gitbook.vercel.app/url/gitbook.com/docs/documentation/zh/fa-bu-wen-dang/authenticated-access/setting-up-oidc)
{% endhint %}

### 概述

要为您的 GitBook 站点设置自定义身份验证系统，请遵循以下关键步骤：

{% stepper %}
{% step %}
[**创建自定义后端以验证您的用户**](#id-1.-create-a-custom-backend-to-authenticate-your-users)

实现一个后端，用于提示用户登录并对其进行身份验证。
{% endstep %}

{% step %}
[**签名并将 JWT 令牌传递给 GitBook**](#id-2.-sign-and-pass-a-jwt-token-to-gitbook)

创建一个 JWT 令牌并使用您站点的私钥对其进行签名。
{% endstep %}

{% step %}
[**配置回退 URL**](#id-3.-configure-a-fallback-url)

配置当未验证的访客访问您的站点时使用的 URL。
{% endstep %}

{% step %}
[**设置多租户验证访问（可选）**](#id-4.-set-up-multi-tenant-authenticated-access)

配置您的后端以处理多个 GitBook 站点的身份验证。
{% endstep %}

{% step %}
[**为自适应内容配置后端（可选）**](#id-5.-configure-your-backend-for-adaptive-content)

配置您的后端以配合 GitBook 中的自适应内容工作。
{% endstep %}
{% endstepper %}

### 1. 创建自定义后端以验证您的用户

为了在用户访问文档之前对其进行身份验证，您需要设置一个可以处理用户登录和身份验证的服务器。

您的后端应当：

* 提示用户使用您首选的身份验证方法登录。
* 验证用户凭证并对其进行认证。
* 在成功认证后生成并签名一个 **JSON Web Token (JWT)** 。
* 将用户重定向到包含该 JWT 的 GitBook。

### 2. 签名并将 JWT 令牌传递给 GitBook

一旦您的后端对用户进行认证，必须 **生成一个 JWT** 并且 **在将其重定向到您的站点时将其传递给 GitBook，** 当 **将他们重定向时。令牌应使用** 私钥 **对其进行签名，** 该私钥在您站点的受众（audience）设置中提供，在 [启用已验证访问](https://gitbook-v2-3sscp147r-gitbook.vercel.app/url/gitbook.com/docs/documentation/zh/fa-bu-wen-dang/enabling-authenticated-access#enable-authenticated-access).

下面的示例应展示在您自定义后端中的登录请求处理程序可能的样子：

{% code title="index.ts" %}

```typescript
import { Request, Response } from 'express';
import * as jose from 'jose';

import { getUserInfo } from '../services/user-info-service';
import { getFeatureFlags } from '../services/feature-flags-service';

const GITBOOK_VISITOR_SIGNING_KEY = process.env.GITBOOK_VISITOR_SIGNING_KEY!;
const GITBOOK_DOCS_URL = 'https://mycompany.gitbook.io/myspace';

export async function handleAppLoginRequest(req: Request, res: Response) {
    // 处理登录请求的业务逻辑
    // 例如，检查凭证并对用户进行认证
    //
    // 例如：
    // const loggedInUser = await authenticateUser(req.body.username, req.body.password);
    
    // 生成已签名的 JWT
    const gitbookVisitorJWT = await new jose.SignJWT({})
        .setProtectedHeader({ alg: 'HS256' })
        .setIssuedAt()
        .setExpirationTime('2h') // 任意的 2 小时过期时间
        .sign(new TextEncoder().encode(GITBOOK_VISITOR_SIGNING_KEY));
    
    // 将用户重定向到包含 URL 中 JWT 令牌的 GitBook
    const redirectURL = `${GITBOOK_DOCS_URL}/?jwt_token=${gitbookVisitorJWT}`;
    res.redirect(redirectURL);
}
```

{% endcode %}

### 3. 配置回退 URL

回退 URL 在未验证的访客尝试访问您的受保护站点时使用。GitBook 会将他们重定向到此 URL。

该 URL 应指向您自定义后端中的一个处理程序，您可以在该处提示他们登录、进行认证，然后将他们带着包含在 URL 中的 JWT 重定向回您的站点。

例如，如果您的登录屏幕位于 `https://example.com/login`, 您应将此值作为回退 URL。

您可以在站点的受众设置的“已验证访问”选项卡中配置此回退 URL。

<figure><img src="https://2111890564-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNkEGS7hzeqa35sMXQZ4X%2Fuploads%2FB48PEdMz1tCDf0Q0lo4d%2FScreenshot%202025-03-25%20at%2015.00.08.png?alt=media&#x26;token=e22fe867-e1f6-44f7-8b4f-a868ac620464" alt="A GitBook screenshot showing where to configure a fallback URL"><figcaption><p>配置回退 URL</p></figcaption></figure>

当重定向到回退 URL 时，GitBook 会在回退 URL 中包含一个 `location` 查询参数，您可以在处理程序中利用该参数将用户重定向到用户的原始位置：

```javascript
const gitbookVisitorJWT = await new jose.SignJWT({})
    .setProtectedHeader({ alg: 'HS256' })
    .setIssuedAt()
    .setExpirationTime('2h') // 任意的 2 小时过期时间
    .sign(new TextEncoder().encode(GITBOOK_VISITOR_SIGNING_KEY));
    
// 使用 jwt_token 查询参数将用户重定向回原始的 GitBook 文档 URL
// 如果提供了 location，用户将被重定向回他们的原始目的地
const redirectURL = `${GITBOOK_DOCS_URL}/${req.query.location || ''}?jwt_token=${gitbookVisitorJWT}`;
res.redirect(redirectURL);
```

{% hint style="warning" %}
因为 GitBook 依赖于 `location` search param - 您不能在回退 URL 中使用它。例如， `https://auth.gitbook.com/?location=something` 不是一个有效的回退 URL。
{% endhint %}

### 4. 设置多租户验证访问（可选）

如果您将 GitBook 作为一个平台向不同客户提供内容，您可能需要设置多租户验证访问。您的身份验证后端需要负责处理多个不同站点的身份验证。在 GitBook 中通过对自定义身份验证后端代码做一些小调整即可实现这一点。

#### 将所有租户添加到您的身份验证服务器

您的身份验证后端需要知道所有预期处理的 GitBook 站点的 JWT 签名密钥和 URL。如果您在组织中有为客户 A 和客户 B 提供的两个站点，您可以想象您的身份验证代码存储这样的映射：

```typescript
const CUSTOMER_A = {
  jwtSigningKey: 'aaa-aaa-aaa-aaa',
  url: 'https://mycompany.gitbook.io/customer-a'
};

const CUSTOMER_B = {
  jwtSigningKey: 'bbb-bbb-bbb-bbb',
  url: 'https://mycompany.gitbook.io/customer-b'
};
```

#### 为您的身份验证服务器提供额外上下文

当 GitBook 无法验证用户的请求时，会将他们重定向到回退 URL。该 URL 指向您的身份验证后端，后端负责对用户进行身份验证并将他们重定向回请求的内容。

为支持多个租户，您的身份验证后端需要知道用户要访问的是哪个 GitBook 站点。该信息可以通过回退 URL 传递。

因此，例如，您可以为每个站点设置如下回退 URL：

<table><thead><tr><th width="150.75390625">GitBook 站点</th><th>回退 URL</th></tr></thead><tbody><tr><td>客户 A 站点</td><td><code>https://auth-backend.acme.org/login?site=customer-a</code></td></tr><tr><td>客户 B 站点</td><td><code>https://auth-backend.acme.org/login?site=customer-b</code></td></tr></tbody></table>

然后，您的身份验证后端可以检查该信息并相应地处理重定向到正确站点：

```javascript
const customerInfo = req.query.site === 'customer-a' ? CUSTOMER_A : CUSTOMER_B;
  
const gitbookVisitorJWT = await new jose.SignJWT({})
    .setProtectedHeader({ alg: 'HS256' })
    .setIssuedAt()
    .setExpirationTime('2h') // 任意的 2 小时过期时间
    .sign(new TextEncoder().encode(customerInfo.jwtSigningKey));
    
// 使用 jwt_token 查询参数将用户重定向回原始的 GitBook 文档 URL
// 如果提供了 location，用户将被重定向回他们的原始目的地
const redirectURL = `${customerInfo.url}/${req.query.location || ''}?jwt_token=${gitbookVisitorJWT}`;
res.redirect(redirectURL);
```

### 5. 为自适应内容配置您的后端（可选）

要在您的验证访问设置中利用自适应内容功能，您可以在自定义后端生成并在将用户重定向到站点时包含在 URL 中的 JWT 的负载中包含额外的用户属性（声明）。

这些在 JWT 中包含的声明将被 GitBook 用于 [动态调整内容](https://gitbook-v2-3sscp147r-gitbook.vercel.app/url/gitbook.com/docs/documentation/zh/fa-bu-wen-dang/adaptive-content/adapting-your-content) 以面向您的站点访客。

综合起来，下面的代码示例演示了如何在 JWT 中包含这些声明，GitBook 可以随后用这些声明为访客调整内容：

{% code title="index.ts" %}

```typescript
import { Request, Response } from 'express';
import * as jose from 'jose';

import { getUserInfo } from '../services/user-info-service';
import { getFeatureFlags } from '../services/feature-flags-service';

const GITBOOK_VISITOR_SIGNING_KEY = process.env.GITBOOK_VISITOR_SIGNING_KEY!;
const GITBOOK_DOCS_URL = 'https://mycompany.gitbook.io/myspace';

export async function handleAppLoginRequest(req: Request, res: Response) {
    // 处理登录请求的业务逻辑
    // 例如，检查凭证并对用户进行认证
    //
    // 例如：
    // const loggedInUser = await authenticateUser(req.body.username, req.body.password);
    
    // 在此示例中，假设有一个已登录的用户对象
    const loggedInUser = { id: '12345' }; // 用实际的认证逻辑替换

    // 检索要传递给 GitBook 的用户信息
    const userInfo = await getUserInfo(loggedInUser.id);
    
    // 生成已签名的 JWT，并将用户属性作为声明包含其中
    const gitbookVisitorClaims = {
        firstName: userInfo.firstName,
        lastName: userInfo.lastName,
        isBetaUser: userInfo.isBetaUser,
        products: userInfo.products.map((product) => product.name),
        featureFlags: await getFeatureFlags({ userId: loggedInUser.id })
    };
    
    const gitbookVisitorJWT = await new jose.SignJWT(gitbookVisitorClaims)
        .setProtectedHeader({ alg: 'HS256' })
        .setIssuedAt()
        .setExpirationTime('2h') // 任意的 2 小时过期时间
        .sign(new TextEncoder().encode(GITBOOK_VISITOR_SIGNING_KEY));
    
    // 将用户重定向到包含 URL 中 JWT 令牌的 GitBook
    const redirectURL = `${GITBOOK_DOCS_URL}/?jwt_token=${gitbookVisitorJWT}`;
    res.redirect(redirectURL);
}
```

{% endcode %}

设置并配置要发送到 GitBook 的正确声明后，前往“[自适应您的内容](https://gitbook-v2-3sscp147r-gitbook.vercel.app/url/gitbook.com/docs/documentation/zh/fa-bu-wen-dang/adaptive-content/adapting-your-content)”以继续配置您的站点。
