# Cookie

{% hint style="info" %}
前往我们的指南，找到一个 [完整演示](https://app.gitbook.com/s/LBGJKQic7BQYBXmVSjy0/docs-personalization-and-authentication/setting-up-adaptive-content) 关于使用 cookie 设置自适应内容。
{% endhint %}

{% hint style="warning" %}
将自适应内容与功能标志一起使用需要向你的应用程序添加代码。

此方法仅在你的网站托管于以下域名下时有效： [自定义域名](https://gitbook-v2-5hpihs24d-gitbook.vercel.app/url/gitbook.com/docs/documentation/zh/docs-site/custom-domain).
{% endhint %}

你可以通过访客浏览器中的 cookie 将访客数据传递到你的文档中。下面是不同方法的概览。

<table data-full-width="false"><thead><tr><th width="335.125">方法</th><th width="266.6015625">使用场景</th><th width="206.58984375">设置难度</th><th width="202">安全性</th><th>格式</th></tr></thead><tbody><tr><td>签名 cookie <code>gitbook-visitor-token</code></td><td>API 测试凭据、客户识别</td><td>需要签名和自定义域名</td><td><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span> 属性只能由后端定义</td><td>JWT</td></tr><tr><td>公共 cookie <code>gitbook-visitor-public</code></td><td>功能标志、角色</td><td>易于设置</td><td><span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span> 访客可以覆盖这些属性</td><td>JSON</td></tr></tbody></table>

### 公共 cookie

要通过公共 cookie 将数据传递到 GitBook，你需要通过设置一个公共 `gitbook-visitor-public` cookie，从你的应用程序发送数据。

以下是一个简单的 JavaScript 示例：

```javascript
import Cookies from 'js-cookie';

const cookieData = {
  isLoggedIn: true,
  isBetaUser: false,
};

Cookies.set('gitbook-visitor-public', JSON.stringify(cookieData), {
  secure: true,
  domain: '*.acme.org',
})
```

{% hint style="warning" %}
通过公共 cookie 传递的数据必须通过一个 [未签名的](https://gitbook.com/docs/publishing-documentation/adaptive-content/enabling-adaptive-content#setting-unsigned-claims) 对象在你的访客架构中定义。
{% endhint %}

### 签名 cookie

要更安全地将数据传递到 GitBook，你需要将数据作为 [JSON Web Token](https://jwt.io/introduction) 从你的应用程序中以名为 `gitbook-visitor-token` 的 cookie 形式发送，并绑定到你的域名。

要进行此设置，你需要调整应用程序的登录流程，以包含以下步骤：

{% stepper %}
{% step %}
**当用户登录到你的应用程序时生成 JWT**

每当用户登录到你的产品时，生成一个包含你已认证用户信息中选定属性的 JWT。
{% endstep %}

{% step %}
**使用站点的访客签名密钥对 JWT 进行签名**

然后，确保使用站点的 **访客签名密钥**对 JWT 进行签名，你可以在启用自适应内容后于站点的受众设置中找到该密钥。
{% endstep %}

{% step %}
**将 JWT 存储在通配符会话 cookie 中**

最后，你需要将包含用户信息的已签名 JWT 存储到一个通配符会话 cookie 中 **位于你的产品域名下**.

例如，如果你的应用程序托管在 `app.acme.org` 域名之后，那么 cookie 需要创建在 `.acme.org` 通配符域名下。
{% endstep %}
{% endstepper %}

以下是一个简单的 TypeScript 示例：

```typescript
import * as jose from 'jose';

import { Request, Response } from 'express';

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_VISITOR_COOKIE_NAME = 'gitbook-visitor-token';


export async function handleAppLoginRequest(req: Request, res: Response) {
   // 处理登录请求的业务逻辑
   // 例如，检查凭据并验证用户身份
   //
   // 例如：
   // const loggedInUser = await authenticateUser(req.body.username, req.body.password);

   // 在认证用户后，从你的数据库或用户服务中检索你希望
   // 传递给 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})
   }
   
   // 使用这些声明生成已签名的 JWT
   const gitbookVisitorJWT = await new jose.SignJWT(gitbookVisitorClaims)
     .setProtectedHeader({ alg: 'HS256' })
     .setIssuedAt()
     .setExpirationTime('2h') // 任意 2 小时过期
     .sign(GITBOOK_VISITOR_SIGNING_KEY);
     
  // 在你的登录处理器响应中包含一个 `gitbook-visitor-token` cookie，
  // 其中包含编码后的 JWT
  res.cookie(GITBOOK_VISITOR_COOKIE_NAME, gitbookVisitorJWT, {
     httpOnly: true,
     secure: process.env.NODE_ENV === 'production',
     maxAge: 2 * 60 * 60 * 1000, // 任意 2 小时过期
     domain: '.acme.org' //
  });
  
  // 登录处理器的其余逻辑，包括将用户重定向到你的应用
  res.redirect('/'); // 示例重定向
}
```
