• 产品简介
  • 快速开始
    • Agent 开发
    • 导入 Git 仓库
    • 从模板开始
    • 直接上传
    • 从 AI 开始
  • 框架指南
    • Agent
    • 前端
      • Vite
      • React
      • Vue
      • Hugo
      • 其他框架
    • 后端
    • 全栈
      • Next.js
      • Nuxt
      • Astro
      • React Router
      • SvelteKit
      • TanStack Start
      • Vike
    • 自定义 404 页面
  • 项目指南
    • 项目管理
    • edgeone.json
    • 缓存配置
    • 构建输出配置
    • 错误码
  • 构建指南
  • 部署指南
    • 概览
    • 触发部署
    • 管理部署
    • 部署按钮
    • 使用 Github Action
    • 使用 Gitlab CI/CD
    • 使用 CNB 插件
    • 使用 IDE 插件
    • 使用 CodeBuddy IDE
  • 域名管理
    • 概览
    • 自定义域名
    • 配置 HTTPS 证书
      • 概览
      • 申请免费证书
      • 使用 SSL 托管证书
    • 配置 DNS 的 CNAME 记录
  • 可观测性
    • 概览
    • 指标分析
    • 日志分析
  • Functions
    • 概览
    • Edge Functions
    • Cloud Functions
      • 概览
      • Node.js
      • Python
      • Go
  • Agents
    • 概览
    • 快速开始
    • 对话存储
    • 可观测
    • 沙箱工具
      • 概览
      • Agent 框架使用
      • 沙箱原子 API
      • 网络搜索工具
    • Agent 鉴权
  • Models
    • 概览
    • 模型与厂商
      • 概览
      • 使用厂商密钥
        • OpenAI
        • Anthropic
        • Google AI Studio
        • DeepSeek
        • MiniMax
        • 混元
        • 智谱
        • 月之暗面
    • 常见问题
  • 存储
    • 概览
    • KV
    • Blob
  • 中间件
  • AI 原生开发
    • Skills
    • MCP
  • Copilot
    • 概览
    • 快速开始
  • API Token
  • EdgeOne CLI
  • 消息通知
  • 集成指南
    • AI
      • 对话型大模型集成
      • 图片大模型集成
    • 数据库
      • Supabase 集成
      • Pages KV 集成
    • 电商
      • Shopify 集成
      • WooCommerce 集成
    • 支付
      • Stripe 集成
      • Paddle 集成
    • CMS
      • WordPress 集成
      • Contentful 集成
      • Sanity 集成
      • Payload 集成
    • 身份验证
      • Supabase 集成
      • Clerk 集成
  • 最佳实践
    • 为网站添加 AI 对话助手
    • AI 对话式部署:使用 Skill 一句话部署项目
    • 使用通用大模型快速搭建 AI 应用
    • 使用边缘 AI 模型快速搭建对话型 AI 站点
    • 使用 Shopify 搭建电商平台
    • 使用 Supabase 和 Stripe 搭建 SaaS 站点
    • 如何快速搭建公司品牌站点
    • 如何快速搭建博客站点
  • 迁移指南
    • 从 Vercel 迁移至 EdgeOne Pages
    • 从 Cloudflare Pages 迁移至 EdgeOne Pages
    • 从 Netlify 迁移至 EdgeOne Pages
  • 排障指南
  • 常见问题
  • 限制与配额
  • 价格与套餐
  • 联系我们
  • 产品动态

Agent 鉴权

Agent 应用通常会调用模型、工具,如果没有登录鉴权,任何人都可以直接访问 Agent 接口,可能带来以下问题:
资源被滥用:未登录用户也能消耗 LLM 和工具调用额度;
接口容易被绕过调用:攻击者可以跳过前端页面,直接请求 /agents/* 等接口。
本文档以实际项目为例,说明如何基于 Makers 平台能力搭建登录鉴权流程:由 Cloud Functions 负责登录注册和 JWT 签发,由平台中间件在边缘节点提前拦截未登录请求。

项目主要文件与职责

文件 / 模块
主要职责
middleware.js
平台中间件,命中受保护路径时先校验 Cookie JWT,失败直接 401,成功 next()
cloud-functions/auth/*
登录、注册、登出、查询当前用户,负责校验账号密码并签发 JWT
agents/chat/index.ts
Agent 示例入口,演示鉴权、流式返回
db/migrations/users.sql
Neon 数据库表结构

实现原理

核心模型

用户浏览器
│ 登录 / 注册
cloud-functions/auth/*
│ 校验账号密码
│ 写入 / 查询 Neon
│ 签发 JWT
浏览器保存 HttpOnly Cookie: jwt_token
│ 调用 Agent
middleware.js
│ 先验 Cookie 里的 JWT
│ 无效:直接 401
│ 有效:next() 透传
Agent Runtime
│ 再次 requireAuth(context)
返回 SSE / Agent 响应

JWT 内容约定

interface JwtPayload {
sub: string; // users.id,UUID v4
username: string; // 用户名
iat: number; // 签发时间,秒级时间戳
exp: number; // 过期时间,秒级时间戳
}

实现流程

登录 / 注册流程

浏览器
│ ① POST /auth/login 或 /auth/register
middleware.js
│ ② /auth/* 不在 matcher 中,直接放行
cloud-functions/auth/*
│ ③ 校验 username / password
│ ④ 查询或写入 Neon users 表
│ ⑤ bcrypt 校验或生成 password_hash
│ ⑥ 使用 JWT_SECRET 签发 JWT
浏览器
│ ⑦ Set-Cookie: jwt_token=...
登录完成
关键点:
/auth/login/auth/register 必须是公开接口。
它们不要放进 middleware.config.matcher
登录成功后只通过 HttpOnly Cookie 保存 token,不把 token 暴露给前端 JS。

Agent 调用流程

浏览器
│ ⑧ POST /chat,自动携带 Cookie: jwt_token=...
middleware.js
│ ⑨ Web Crypto 校验 JWT
│ 失败:401
│ 成功:next()
Agent Runtime
│ ⑩ requireAuth(context) 再验一次 JWT
浏览器
│ ⑪ SSE 流式返回 Agent 响应
关键点:
中间件验签成功后只透传原请求。
Agent 自己从 Cookie 读取 JWT,并独立验签(可选)。

平台中间件关键实现

文件:middleware.js
职责:命中受保护路径 → 校验 Cookie JWT → 失败 401 / 成功 next()

配置受保护路径

export const config = {
matcher: [
'/chat/:path*',
'/stop/:path*',
'/history/:path*',
'/agents/:path*',
],
};
注意:
matcher 是中间件保护范围的唯一来源。
/auth/* 不要加入 matcher。
静态资源、前端页面路由一般也不需要加入 matcher。

主逻辑

export async function middleware(context) {
const { request, next, env } = context;

const token = readCookie(request.headers, 'jwt_token');
if (!token) return unauthorized('no auth cookie');

try {
await verifyJwt(token, env.JWT_SECRET);
} catch (e) {
return unauthorized(e.message || 'verify failed');
}

return next();
}

验签要点

中间件运行在边缘 V8 环境,使用 Web Crypto:
const key = await crypto.subtle.importKey(
'raw',
utf8ToBytes(secret),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign', 'verify'],
);
验签时必须检查:
检查项
目的
token 是否是三段式
防止 malformed token
header.alg === 'HS256'
alg=none 和算法混淆
HMAC 签名是否一致
确认 token 未被篡改
payload.exp 是否过期
防止旧 token 长期有效

Cloud Functions 关键实现

目录:cloud-functions/
职责:注册 / 登录 / 当前用户信息 / 登出

文件结构

文件
作用
auth/register/index.ts
注册用户,写入 Neon,颁发 JWT
auth/login/index.ts
校验密码,颁发 JWT
auth/user/index.ts
从 Cookie 判断当前登录用户
auth/logout/index.ts
清空 Cookie

Agent 侧关键实现

文件示例:agents/chat/index.ts

入口第一步验签(可选)

中间件的价值是早拒:在边缘节点挡掉未登录请求,减少 Agent Runtime、Sandbox、LLM 的成本。但中间件不是最终安全边界,您可以在 Agent 侧再做一次验签。
import { requireAuth, AuthError, unauthorizedResponse } from '../_jwt';
export async function onRequest(context: any) {
let auth;
try {
auth = requireAuth(context);
} catch (e) {
if (e instanceof AuthError) {
return unauthorizedResponse(e.reason);
}
throw e;
}
// 从这里开始,才能执行 Agent 业务逻辑
}

数据库配置与实现

Neon 是 Serverless Postgres,此方案用它保存用户表,并通过 @neondatabase/serverless 以 HTTPS 方式访问,您也可以选择其它第三方数据库。

配置步骤

1. Neon 控制台创建项目;
2. 获取连接串,格式类似:
postgresql://<user>:<password>@<host>/<db>?sslmode=require
3. 在 EdgeOne Makers 项目环境变量中配置:
变量
必填
说明
DATABASE_URL
Neon 连接串,建议带 ?sslmode=require
JWT_SECRET
JWT 签名密钥,三层必须一致
本地开发时,在 .env 中配置同名变量。

数据库表结构

CREATE EXTENSION IF NOT EXISTS pgcrypto;

CREATE TABLE IF NOT EXISTS users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
username VARCHAR(64) NOT NULL,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE UNIQUE INDEX IF NOT EXISTS users_username_lower_uniq
ON users (LOWER(username));
说明:
id 由 Postgres gen_random_uuid() 自动生成。
password_hash 只保存 bcrypt 哈希,不保存明文密码。
LOWER(username) 唯一索引用于避免 Alicealice 同时注册。

接入步骤

如果你要把这套方案接到自己的 Agent 项目,按这个顺序做:
1. 创建 Neon 数据库,执行 db/migrations/users.sql
2. 配置 DATABASE_URLJWT_SECRET
3. 复制 cloud-functions/auth/*cloud-functions/_jwt.tscloud-functions/_db.tscloud-functions/_validate.ts
4. 配置 middleware.jsmatcher,覆盖所有受保护 Agent 路径;
5. 在每个 Agent 入口第一步加入 requireAuth(context)


ai-agent
你可以这样问我
我可以部署哪些类型的应用程序?