# 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-q67etdj25-gitbook.vercel.app/url/gitbook.com/docs/documentation/zh/publishing-documentation/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('/'); // 示例重定向
}
```
