跳到主要内容

认证指南

本文档深入介绍 Lovrabet OpenAPI 的认证机制、Token 管理和最佳实践。

认证概述

Lovrabet OpenAPI 采用基于 HMAC-SHA256 签名的认证机制,根据运行环境和使用场景,支持三种认证模式:

认证模式适用场景密钥要求
服务端模式Node.js 服务端、SSRaccessKey
浏览器 Token 模式浏览器公开数据访问预生成 token + timestamp
浏览器 Cookie 模式已登录用户私有数据无需密钥(使用 Cookie)
SDK 自动处理

官方 SDK 会自动根据提供的参数选择合适的认证模式,无需手动指定。

认证凭证

您需要的凭证

凭证名称说明获取方式示例
App Code应用唯一标识联系商务经理app-c2dd52a2
Access Key访问密钥联系商务经理ak-xxxxxxxxxxxxx
Dataset Code数据集标识联系商务经理0fefba76fe29...ff
安全提示

Access Key 是敏感信息,请妥善保管,不要泄露或硬编码到代码中。

模式 1: 服务端认证(accessKey)

适用于 Node.js 服务端、Next.js SSR、API 路由等场景。

基础用法

import { createClient } from "@lovrabet/sdk";

const client = createClient({
appCode: "your-app-code",
accessKey: process.env.LOVRABET_ACCESS_KEY, // ✅ 从环境变量读取
models: {
users: {
tableName: "users",
datasetCode: "your-dataset-code",
},
},
});

// SDK 自动生成 Token 并处理认证
const users = await client.models.users.filter();

工作原理

当提供 accessKey 时:

  1. SDK 使用 accessKey 和当前时间戳
  2. 通过 HMAC-SHA256 算法实时生成 Token
  3. 自动在请求头中添加认证信息:
    • X-App-Code: 应用标识
    • X-Dataset-Code: 数据集标识
    • X-Time-Stamp: 当前时间戳
    • X-Token: 生成的签名

Next.js Server Component 示例

// app/users/page.tsx (Server Component)
import { createClient } from "@lovrabet/sdk";

// 在服务端组件中创建客户端
const client = createClient({
appCode: process.env.LOVRABET_APP_CODE!,
accessKey: process.env.LOVRABET_ACCESS_KEY!,
models: {
users: {
tableName: "users",
datasetCode: process.env.LOVRABET_DATASET_CODE!,
},
},
});

export default async function UsersPage() {
// 直接在服务端调用
const { tableData: users } = await client.models.users.filter();

return (
<div>
{users.map((user) => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
}

环境变量配置

创建 .env.local 文件:

LOVRABET_APP_CODE=your-app-code
LOVRABET_ACCESS_KEY=your-access-key
LOVRABET_DATASET_CODE=your-dataset-code
安全最佳实践
  • ✅ 使用环境变量存储 Access Key
  • .env.local 加入 .gitignore
  • ✅ 不同环境使用不同的密钥
  • ❌ 不要硬编码密钥到代码中

模式 2: 浏览器 Token 认证(预生成)

适用于浏览器端公开数据访问、未登录用户等场景。

重要安全提示

绝对不能在浏览器代码中使用 accessKey!必须在服务端生成 Token,然后传递给浏览器使用。

步骤 1: 服务端生成 Token

使用 generateOpenApiToken() 函数生成 Token:

// app/api/token/route.ts
import { generateOpenApiToken } from "@lovrabet/sdk";
import { NextResponse } from "next/server";

export async function GET() {
try {
const result = await generateOpenApiToken({
appCode: process.env.LOVRABET_APP_CODE!,
datasetCode: process.env.LOVRABET_DATASET_CODE!,
accessKey: process.env.LOVRABET_ACCESS_KEY!,
// secretKey: "lovrabet", // 可选,默认为 "lovrabet"
// timestamp: Date.now(), // 可选,默认为当前时间
});

// result 包含: { token, timestamp, expiresAt }
return NextResponse.json(result);
} catch (error) {
return NextResponse.json({ error: "Token 生成失败" }, { status: 500 });
}
}

返回数据结构:

{
token: string; // 生成的 Token
timestamp: number; // 时间戳(毫秒)
expiresAt: Date; // 过期时间
}

步骤 2: 浏览器使用 Token

// app/users/client-page.tsx
"use client";

import { createClient } from "@lovrabet/sdk";
import { useEffect, useState } from "react";

export default function ClientUsersPage() {
const [users, setUsers] = useState([]);

useEffect(() => {
async function init() {
// 1. 从服务端获取 Token
const { token, timestamp } = await fetch("/api/token").then((r) =>
r.json()
);

// 2. 创建客户端(使用 token 和 timestamp)
const client = createClient({
appCode: "your-app-code",
token: token, // 预生成的 token
timestamp: timestamp, // 对应的时间戳
models: {
users: { tableName: "users", datasetCode: "your-dataset-code" },
},
});

// 3. 查询数据
const { tableData } = await client.models.users.filter();
setUsers(tableData);
}

init();
}, []);

return (
<div>
{users.map((user) => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
}

工作原理

当提供 tokentimestamp 时:

  1. SDK 直接使用预生成的 Token
  2. 不再实时计算签名
  3. 在请求头中添加:
    • X-Token: 预生成的 Token
    • X-Time-Stamp: 对应的时间戳
    • X-App-CodeX-Dataset-Code

Token 有效期管理

Token 有效期为 10 分钟(600 秒),过期后需要刷新。

检查 Token 是否即将过期

import { isTokenExpiring, getTokenRemainingTime } from "@lovrabet/sdk";

const timestamp = Date.now();

// 检查是否即将过期(默认缓冲时间 1 分钟)
if (isTokenExpiring(timestamp)) {
console.log("Token 即将过期,需要刷新");
}

// 检查是否即将过期(自定义缓冲时间 2 分钟)
if (isTokenExpiring(timestamp, 120000)) {
console.log("2 分钟内将过期");
}

// 获取剩余时间(毫秒)
const remaining = getTokenRemainingTime(timestamp);
console.log(`Token 剩余 ${remaining / 1000}`);

自动刷新 Token

"use client";

import {
createClient,
isTokenExpiring,
getTokenRemainingTime,
} from "@lovrabet/sdk";
import { useEffect, useState } from "react";

export default function UsersWithAutoRefresh() {
const [client, setClient] = useState(null);
const [timestamp, setTimestamp] = useState(null);
const [remainingTime, setRemainingTime] = useState(null);

// 初始化
useEffect(() => {
fetchTokenAndCreateClient();
}, []);

// 定期检查 Token 有效期
useEffect(() => {
if (!timestamp) return;

const interval = setInterval(() => {
const remaining = getTokenRemainingTime(timestamp);
setRemainingTime(remaining);

// 提前 1 分钟刷新
if (isTokenExpiring(timestamp, 60000)) {
console.log("Token 即将过期,刷新中...");
fetchTokenAndCreateClient();
}
}, 10000); // 每 10 秒检查一次

return () => clearInterval(interval);
}, [timestamp]);

async function fetchTokenAndCreateClient() {
const { token, timestamp: newTimestamp } = await fetch("/api/token").then(
(r) => r.json()
);

const newClient = createClient({
appCode: "your-app-code",
token: token,
timestamp: newTimestamp,
models: {
users: { tableName: "users", datasetCode: "your-dataset-code" },
},
});

setClient(newClient);
setTimestamp(newTimestamp);
}

// 显示剩余时间
return (
<div>
<p>Token 剩余: {Math.floor((remainingTime || 0) / 1000)}</p>
{/* ... 其他内容 */}
</div>
);
}

批量生成 Token

如果需要为多个数据集生成 Token,使用 TokenGenerator 类:

import { TokenGenerator } from "@lovrabet/sdk";

const generator = new TokenGenerator(
process.env.LOVRABET_ACCESS_KEY!,
"lovrabet" // secretKey,可选
);

// 批量生成
const tokens = await generator.generateBatch({
appCode: "your-app-code",
datasets: [
{ name: "users", code: "dataset-001" },
{ name: "orders", code: "dataset-002" },
{ name: "products", code: "dataset-003" },
],
// timestamp: Date.now(), // 可选,默认当前时间
});

// 使用生成的 tokens
console.log(tokens.users.token);
console.log(tokens.users.timestamp);
console.log(tokens.users.expiresAt);

console.log(tokens.orders.token);
console.log(tokens.products.token);

// 返回一个 API 端点
export async function GET() {
return NextResponse.json(tokens);
}

TokenGenerator 方法

class TokenGenerator {
constructor(accessKey: string, secretKey?: string);

// 生成单个 Token
generate(params: {
appCode: string;
datasetCode: string;
timestamp?: number;
}): Promise<TokenResult>;

// 批量生成 Token
generateBatch(params: {
appCode: string;
datasets: Array<{ name: string; code: string }>;
timestamp?: number;
}): Promise<Record<string, TokenResult>>;
}

适用于已登录用户访问私有数据的场景。

使用方法

"use client";

import { createClient } from "@lovrabet/sdk";

// 不提供任何认证信息
const client = createClient({
appCode: "your-app-code",
models: {
orders: { tableName: "orders", datasetCode: "your-dataset-code" },
},
});

// 请求会自动携带浏览器的登录 Cookie
const { tableData } = await client.models.orders.filter();

工作原理

当未提供 accessKeytoken 时:

  1. SDK 使用 WebAPI 模式
  2. 请求会自动携带浏览器的 Cookie
  3. 使用用户的登录态进行认证
  4. 适用于已登录用户访问自己的数据

应用场景

  • ✅ 用户订单列表
  • ✅ 个人资料数据
  • ✅ 用户收藏/购物车
  • ❌ 公开数据访问(未登录用户)

认证模式选择

决策树

是否在服务端?
├─ 是 → 使用 accessKey 模式(模式 1)
└─ 否(浏览器端)
├─ 用户已登录且访问私有数据?
│ ├─ 是 → 使用 Cookie 模式(模式 3)
│ └─ 否 → 使用预生成 Token 模式(模式 2)
└─ 公开数据访问?
└─ 是 → 使用预生成 Token 模式(模式 2)

对比表

特性服务端模式Token 模式Cookie 模式
运行环境Node.js 服务端浏览器浏览器
认证信息accessKeytoken + timestampCookie
Token 生成实时生成预生成无需 Token
有效期无限制10 分钟依赖登录态
安全性最高
适用场景SSR、API 路由公开数据访问私有数据访问

错误处理

认证相关错误码

错误码说明解决方案
1002签名验证失败检查 Access Key 是否正确
1003时间戳过期Token 已过期,重新生成
1004应用不存在检查 App Code 是否正确
1005数据集不存在检查 Dataset Code 是否正确
1006无访问权限确认应用有该数据集的访问权限

错误处理示例

import { LovrabetError } from "@lovrabet/sdk";

try {
const users = await client.models.users.filter();
} catch (error) {
if (error instanceof LovrabetError) {
switch (error.statusCode) {
case 1002:
console.error("签名验证失败,请检查 Access Key");
break;
case 1003:
console.error("Token 已过期,正在刷新...");
// 重新获取 token
await fetchTokenAndCreateClient();
break;
case 1006:
console.error("无权访问该数据集");
break;
default:
console.error("API 错误:", error.message);
}
} else {
console.error("未知错误:", error);
}
}

最佳实践

1. 凭证安全

关键安全规则
  • 服务端: 使用环境变量存储 Access Key
  • 浏览器: 使用预生成 Token,绝不暴露 Access Key
  • ✅ 定期更换 Access Key
  • ✅ 不同环境使用不同的密钥
  • 绝不在客户端代码中硬编码 Access Key
  • 绝不将 Access Key 提交到代码仓库

错误示例:

// ❌ 危险!会暴露 Access Key
const client = createClient({
accessKey: "ak-xxxxx", // 不要这样做!
});

正确示例:

// ✅ 服务端:使用环境变量
const client = createClient({
accessKey: process.env.LOVRABET_ACCESS_KEY,
});

// ✅ 浏览器:使用预生成 Token
const { token } = await fetch("/api/token").then((r) => r.json());
const client = createClient({ token });

2. 客户端实例复用

// ✅ 推荐:复用客户端实例
const client = createClient({
/* 配置 */
});

const users = await client.models.users.filter();
const orders = await client.models.orders.filter();

// ❌ 避免:重复创建客户端
const client1 = createClient({
/* 配置 */
});
const users = await client1.models.users.filter();

const client2 = createClient({
/* 配置 */
}); // 不必要
const orders = await client2.models.orders.filter();

3. Token 刷新策略

// 提前刷新,避免过期
if (isTokenExpiring(timestamp, 60000)) {
// 提前 1 分钟刷新
await refreshToken();
}

// 错误时重试
try {
await api.call();
} catch (error) {
if (error.statusCode === 1003) {
// Token 过期,刷新后重试
await refreshToken();
await api.call();
}
}

高级用法

动态更新 Token

const client = createClient({
appCode: "your-app-code",
models: {
/* ... */
},
});

// 后续更新 token
client.setToken(newToken, newTimestamp);

自定义请求选项

const client = createClient({
appCode: "your-app-code",
accessKey: process.env.LOVRABET_ACCESS_KEY,
models: {
/* ... */
},
options: {
timeout: 30000, // 30 秒超时
// 其他 fetch 选项
},
});

签名算法详解(高级)

仅供参考

SDK 已自动处理签名生成,通常无需关心底层实现。

签名生成步骤:

  1. 收集参数:

    {
    accessKey: "your-access-key",
    timeStamp: "1758903130713",
    appCode: "app-c2dd52a2",
    datasetCode: "0fefba76fe29..."
    }
  2. 按字典序排序并拼接:

    accessKey=your-access-key&appCode=app-c2dd52a2&datasetCode=0fefba76fe29...&timeStamp=1758903130713
  3. 使用 HMAC-SHA256 计算签名:

    const token = crypto
    .createHmac("sha256", secretKey)
    .update(sortedParams, "utf8")
    .digest("base64");
  4. 添加到请求头:

    X-Token: jdqqGtzecF2I6FIW0s2xv0YRIprUqt0FLEJPYCgGB+4=

常见问题

Q: 为什么推荐使用 SDK?

A: SDK 封装了所有认证细节,包括:

  • ✅ 自动生成签名
  • ✅ 处理时间戳
  • ✅ Token 生命周期管理
  • ✅ 错误处理和重试
  • ✅ TypeScript 类型支持

Q: Token 有效期是多久?

A: Token 有效期为 10 分钟(600 秒)。建议提前 1-2 分钟刷新,避免过期。

Q: 如何在浏览器中安全使用?

A: 绝不在浏览器中使用 accessKey,而是:

  1. 服务端生成 Token
  2. 通过 API 返回给前端
  3. 前端使用预生成的 Token

Q: Access Key 泄露了怎么办?

A: 立即采取行动:

  1. 联系商务经理更换新的 Access Key
  2. 停用旧的 Access Key
  3. 更新所有使用旧 Key 的应用
  4. 审计可能受影响的数据

Q: 可以自定义 Token 有效期吗?

A: 不可以,Token 有效期固定为 10 分钟。这是出于安全考虑的设计。

下一步

需要帮助?

如遇到认证相关问题:

  1. 检查本文档的错误处理部分
  2. 查看 GitHub Issues
  3. 联系商务经理获取技术支持