@authhero/cloudflare-adapter

中文文档
4.2.0发布于 2026/11/05AGPL-3.0-onlyTypeScriptESM + CJS构建来源已验证近 30 天下载 1716

为AuthHero提供Cloudflare专用适配器,提供与Cloudflare服务的集成.

中文使用文档
文档目录30 节
  1. 特征
  2. 安装
  3. 使用量
  4. 带有分析引擎日志(推荐给工人)
  5. 带有 R2 SQL 日志( HTTP 端点模式)
  6. 服务约束模式( 云旗工人)
  7. 通道模式( 多重目标)
  8. 适配器
  9. 自定义域适应器
  10. 缓存适配器
  11. 日志适配器(R2 SQL +管道)
  12. 日志适配器( 分析引擎)
  13. 分析引擎)
  14. 设置
  15. 数据Schema
  16. 地理适应器
  17. 特征
  18. Cloudflare 设置
  19. 配置
  20. 已使用云旗信头
  21. 响应格式
  22. 与 Auth Hero 合并
  23. 替代: IP 地理位置数据库
  24. 环境变量
  25. 类型脚本
  26. 代码执行器
  27. WorkerLoaderCodeExecutor ——有活力劳动者
  28. DispatchNamespaceCodeExecutor - 平台工人组织
  29. 相关文档
  30. 许可证

@authhero/cloudflare-适应器

为AuthHero提供Cloudflare专用适配器,提供与Cloudflare服务的集成.

特征

本包提供适配器,用于:

  • 自定义域 - 通过 Cloudflare API 管理自定义域
  • 缓存 使用 Cloudflare 的缓存 API 进行缓存
  • 地理 (可选) - 从 Cloudflare 请求头提取地理信息
  • 日志 (可选) - 认证日志的两个选项:
    • 分析引擎 - 低纬度写作,使用SQL查询(保留90天)
    • R2 SQL + 管道 - 长期储存,无限保留

安装

npm install @authhero/cloudflare-adapter

使用量

import createAdapters from "@authhero/cloudflare-adapter";

// In a Cloudflare Worker
interface Env {
  AUTH_LOGS: AnalyticsEngineDataset;
  CLOUDFLARE_ACCOUNT_ID: string;
  ANALYTICS_ENGINE_API_TOKEN: string;
}

export default {
  async fetch(request: Request, env: Env) {
    const adapters = createAdapters({
      // Custom domains configuration
      zoneId: "your-cloudflare-zone-id",
      authKey: "your-cloudflare-api-key",
      authEmail: "your-cloudflare-email",
      customDomainAdapter: yourDatabaseCustomDomainsAdapter,

      // Analytics Engine logs (low latency writes)
      analyticsEngineLogs: {
        analyticsEngineBinding: env.AUTH_LOGS,
        accountId: env.CLOUDFLARE_ACCOUNT_ID,
        apiToken: env.ANALYTICS_ENGINE_API_TOKEN,
      },
    });

    const { customDomains, cache, geo, logs } = adapters;
    // ...
  },
};

带有 R2 SQL 日志( HTTP 端点模式)

import createAdapters from "@authhero/cloudflare-adapter";

const adapters = createAdapters({
  // Custom domains configuration
  zoneId: "your-cloudflare-zone-id",
  authKey: "your-cloudflare-api-key",
  authEmail: "your-cloudflare-email",
  customDomainAdapter: yourDatabaseCustomDomainsAdapter,

  // Cache configuration (optional)
  cacheName: "default",
  defaultTtlSeconds: 3600,
  keyPrefix: "authhero:",

  // Geo adapter configuration (optional) - automatically included when getHeaders is provided
  getHeaders: () => {
    // In Cloudflare Workers, you'd typically pass request headers
    // Cloudflare automatically adds cf-ipcountry, cf-ipcity, etc.
    return request.headers;
  },

  // R2 SQL logs configuration (optional) - HTTP mode
  r2SqlLogs: {
    pipelineEndpoint: "https://your-stream-id.ingest.cloudflare.com",
    authToken: process.env.R2_SQL_AUTH_TOKEN,
    warehouseName: process.env.R2_WAREHOUSE_NAME,
    namespace: "default",
    tableName: "logs",
  },
});

// Use the adapters
const { customDomains, cache, geo, logs } = adapters;

服务约束模式( 云旗工人)

interface Env {
  PIPELINE_SERVICE: { fetch: typeof fetch };
  R2_SQL_AUTH_TOKEN: string;
  R2_WAREHOUSE_NAME: string;
}

export default {
  async fetch(request: Request, env: Env) {
    const adapters = createAdapters({
      zoneId: "your-cloudflare-zone-id",
      authKey: "your-cloudflare-api-key",
      authEmail: "your-cloudflare-email",
      customDomainAdapter: yourDatabaseCustomDomainsAdapter,

      // Geo adapter - extract location from Cloudflare headers
      getHeaders: () => Object.fromEntries(request.headers),

      // R2 SQL logs with service binding
      r2SqlLogs: {
        pipelineBinding: env.PIPELINE_SERVICE,
        authToken: env.R2_SQL_AUTH_TOKEN,
        warehouseName: env.R2_WAREHOUSE_NAME,
      },
    });

    // Use adapters.logs and adapters.geo
  },
};

通道模式( 多重目标)

使用核心 createPassthroughAdapter 用于同步日志到多个目的地的功能 :

import { createPassthroughAdapter } from "@authhero/adapter-interfaces";
import createAdapters, {
  createR2SQLLogsAdapter,
  createAnalyticsEngineLogsAdapter,
} from "@authhero/cloudflare-adapter";

// Primary adapter (e.g., existing database)
const databaseAdapter = createDatabaseLogsAdapter();

// Cloudflare logs adapters for secondary syncing
const r2SqlAdapter = createR2SQLLogsAdapter({
  pipelineEndpoint: "https://your-stream-id.ingest.cloudflare.com",
  authToken: process.env.R2_SQL_AUTH_TOKEN,
  warehouseName: process.env.R2_WAREHOUSE_NAME,
});

const analyticsEngineAdapter = createAnalyticsEngineLogsAdapter({
  analyticsEngineBinding: env.AUTH_LOGS,
  accountId: env.CLOUDFLARE_ACCOUNT_ID,
  apiToken: env.ANALYTICS_ENGINE_API_TOKEN,
});

// Create passthrough adapter - writes to primary and all secondaries
const logsAdapter = createPassthroughAdapter({
  primary: databaseAdapter,
  secondaries: [
    { adapter: { create: r2SqlAdapter.create } },
    { adapter: { create: analyticsEngineAdapter.create } },
  ],
});

// logsAdapter.create() writes to database, R2 SQL Pipeline, and Analytics Engine
// logsAdapter.get() and logsAdapter.list() read from database only

适配器

自定义域适应器

通过 Cloudflare API 管理自定义域.

配置

{
  zoneId: string;              // Your Cloudflare zone ID
  authKey: string;             // Your Cloudflare API key
  authEmail: string;           // Your Cloudflare account email
  enterprise?: boolean;        // Whether using Cloudflare Enterprise (default: false)
  customDomainAdapter: CustomDomainsAdapter; // Database adapter for storing domain data
}

方法

  • create(tenantId, domain) - 创建自定义域
  • get(tenantId, domainId) - 获取自定义域
  • getByDomain(domain) - 按域名获取域名
  • list(tenantId, params) - 列出自定义域
  • remove(tenantId, domainId) - 删除自定义域
  • update(tenantId, domainId, data) - 更新自定义域

缓存适配器

使用 Cloudflare 的缓存 API 提供缓存 .

配置

{
  cacheName?: string;          // Cache name (default: "default")
  defaultTtlSeconds?: number;  // Default TTL in seconds (default: undefined)
  keyPrefix?: string;          // Key prefix for namespacing (default: undefined)
}

方法

  • get<T>(key) - 从缓存中获取值
  • set<T>(key, value, ttl?) - 以可选 TTL 设置缓存值
  • delete(key) - 从缓存中删除一个值

示例

// Set a value with 1 hour TTL
await cache.set("user:123", userData, 3600);

// Get a value
const user = await cache.get("user:123");

// Delete a value
await cache.delete("user:123");

日志适配器(R2 SQL +管道)

将认证日志写入 Cloudflare R2 使用管道进行摄取,而R2 SQL 用于查询.

建筑

这个适配器使用两个Cloudflare服务:

  • 管道: 将日志数据输入 R2 的 HTTP 端点
  • R2小口径: 用于分析以 Apache Iceberg 格式存储的日志的查询接口

先决条件

  1. 创建 R2 桶并启用 R2 数据目录数字 :
npx wrangler r2 bucket create my-authhero-logs
npx wrangler r2 bucket catalog enable my-authhero-logs

注意输出中的"Warehouse"名称 - 你以后需要它.

  1. 创建 API 令牌

在云花板上:

  • 转到 R2 对象存储
  • 选择“ 管理 API 令牌 ”
  • 使用管理员读取和写入权限创建一个令牌
  • 保存符号值
  1. 创建计划文件 (单位:千美元)schema.json:
{
  "fields": [
    { "name": "tenant_id", "type": "string", "required": true },
    { "name": "type", "type": "string", "required": true },
    { "name": "date", "type": "string", "required": true },
    { "name": "description", "type": "string", "required": false },
    { "name": "ip", "type": "string", "required": false },
    { "name": "user_agent", "type": "string", "required": true },
    { "name": "details", "type": "string", "required": false },
    { "name": "isMobile", "type": "int64", "required": false },
    { "name": "user_id", "type": "string", "required": false },
    { "name": "user_name", "type": "string", "required": false },
    { "name": "connection", "type": "string", "required": false },
    { "name": "connection_id", "type": "string", "required": false },
    { "name": "client_id", "type": "string", "required": false },
    { "name": "client_name", "type": "string", "required": false },
    { "name": "audience", "type": "string", "required": false },
    { "name": "scope", "type": "string", "required": false },
    { "name": "strategy", "type": "string", "required": false },
    { "name": "strategy_type", "type": "string", "required": false },
    { "name": "hostname", "type": "string", "required": false },
    { "name": "auth0_client", "type": "string", "required": false },
    { "name": "log_id", "type": "string", "required": true },
    { "name": "country_code", "type": "string", "required": false },
    { "name": "city_name", "type": "string", "required": false },
    { "name": "latitude", "type": "string", "required": false },
    { "name": "longitude", "type": "string", "required": false },
    { "name": "time_zone", "type": "string", "required": false },
    { "name": "continent_code", "type": "string", "required": false }
  ]
}
  1. 创建管道数字 :
npx wrangler pipelines setup

跟随提示:

  • 管道名称数字 : authhero-logs
  • 启用 HTTP 端点数字 : yes
  • 需要认证数字 : no (或 yes 如果您想要额外的安全)
  • 配置自定义 CORS 来源数字 : no
  • Schema 定义数字 : Load from file
  • Schema 文件路径数字 : schema.json
  • 目标类型数字 : Data Catalog Table
  • R2桶名称数字 : my-authhero-logs
  • 命名空间数字 : default
  • 表格名称数字 : logs
  • 目录 API 令牌: 从第 2 步输入您的令牌
  • 压缩数字 : zstd
  • 大小达到时滚动文件( MB)数字 : 100
  • 时间到达时滚动文件( 秒)数字 : 300 (5分钟)
  • SQL 转换数字 : Use simple ingestion query

重要: 从输出中保存 HTTP 端点 URL(例如, https://abc123.ingest.cloudflare.com(中文(简体) )

配置

R2 SQL 日志适配器支持三种使用模式:

1. HTTP 端点模式(默认)

当从 Cloudflare 工作端外调用管道时使用此模式 :

{
  pipelineEndpoint: string;    // Pipeline HTTP endpoint URL for ingesting logs
  authToken: string;           // R2 SQL API token for querying logs
  warehouseName: string;       // R2 warehouse name
  namespace?: string;          // Catalog namespace (default: "default")
  tableName?: string;          // Table name (default: "logs")
  apiBaseUrl?: string;         // R2 SQL API base URL
  timeout?: number;            // HTTP timeout in ms (default: 30000)
}
2. 管道捆绑方式(工人)

在有管道绑定的 Cloudflare Worker 内部运行时使用此模式 。 这是最有效的模式,因为它使用没有HTTP间接费用的直接捆绑.

{\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}我还得说

[[pipelines]]
binding = "AUTH_LOGS_STREAM"
pipeline = "your-pipeline-id"

类型脚本 :

interface Env {
  AUTH_LOGS_STREAM: Pipeline;
  R2_SQL_AUTH_TOKEN: string;
  R2_WAREHOUSE_NAME: string;
}

export default {
  async fetch(request: Request, env: Env) {
    const adapters = createAdapters({
      zoneId: "your-zone-id",
      authKey: "your-api-key",
      authEmail: "your-email",
      customDomainAdapter: yourDbAdapter,

      r2SqlLogs: {
        pipelineBinding: env.AUTH_LOGS_STREAM,
        authToken: env.R2_SQL_AUTH_TOKEN,
        warehouseName: env.R2_WAREHOUSE_NAME,
      },
    });

    const { logs } = adapters;
    // Use logs adapter
  },
};

管道绑定使用 .send() 直接数据摄入方法.

3. 传通模式(刷新另一个适配器)

使用核心 createPassthroughAdapter 用于向 R2 SQL 管道和另一个日志适配器发送日志的功能 :

import { createPassthroughAdapter } from "@authhero/adapter-interfaces";
import { createR2SQLLogsAdapter } from "@authhero/cloudflare-adapter";

// Primary adapter (e.g., existing database)
const databaseAdapter = createDatabaseLogsAdapter();

// R2 SQL Pipeline adapter
const r2SqlAdapter = createR2SQLLogsAdapter({
  pipelineEndpoint: "https://your-stream-id.ingest.cloudflare.com",
  authToken: env.R2_SQL_AUTH_TOKEN,
  warehouseName: env.R2_WAREHOUSE_NAME,
});

// Create passthrough adapter
const logsAdapter = createPassthroughAdapter({
  primary: databaseAdapter,
  secondaries: [
    {
      adapter: { create: r2SqlAdapter.create },
      onError: (err) => console.error("R2 SQL sync failed:", err),
    },
  ],
});

通过模式 :

  • create() 首先给主适配器打电话,然后在背景中发送到第二位
  • get() 财务报告和审定财务报表 list() 仅从主适配器读取
  • 二次错误被记录,但不要失败操作

方法

  • create(tenantId, log) - 创建日志条目(发送到管道)
  • get(tenantId, logId) - 获取日志条目(取出R2 SQL)
  • list(tenantId, params) - 有页码和过滤的列表日志(取出R2 SQL)

示例

// Create a log
const log = await logs.create("tenant-123", {
  type: "s", // Successful login
  date: new Date().toISOString(),
  ip: "192.168.1.100",
  user_agent: "Mozilla/5.0...",
  isMobile: false,
  user_id: "user-456",
  client_id: "app-789",
  description: "User logged in successfully",
});

// List logs with filtering
const result = await logs.list("tenant-123", {
  page: 0,
  per_page: 50,
  include_totals: true,
  sort: {
    sort_by: "date",
    sort_order: "desc",
  },
  q: "user_id:user-456", // Lucene-style filter
});

用 R2 SQL 查询日志

您可以直接使用 Wrangler CLI 查询日志 :

# Set up authentication
export WRANGLER_R2_SQL_AUTH_TOKEN=your_api_token

# Query logs
npx wrangler r2 sql query "your_warehouse" "
  SELECT * FROM default.logs
  WHERE tenant_id = 'tenant-123'
  AND type = 's'
  ORDER BY date DESC
  LIMIT 100
"

# Count logs by type
npx wrangler r2 sql query "your_warehouse" "
  SELECT type, COUNT(*) as count
  FROM default.logs
  WHERE tenant_id = 'tenant-123'
  GROUP BY type
"

日志适配器( 分析引擎)

将认证日志写入 Cloudflare 工人分析引擎,用于低纬度写作和基于 SQL 的查询.

建筑

这个适配器使用 Cloudflare 的工人分析引擎:

  • 写入: 使用 Fire- and-forget 写入 writeDataPoint() (无 HTTP 间隔)
  • 查询: SQL API 用于分析存储在分析引擎中的日志

何时使用分析引擎对 R2 SQL

特性分析引擎R2 SQL + 管道
写入空闲度~0ms (火与遗忘) :~50-100毫米(HTTP)
数据保留90天(免费),可配置无限制
查询语言SQL (类似 ClickHouse)SQL (冰堡) (英语)
最佳服务实时分析, 最近的日志长期储存、遵守
定价可自由分级每个存储+查询付费

先决条件

  1. 创建分析引擎数据集数字 :

配置在 wrangler.toml数字 :

[[analytics_engine_datasets]]
binding = "AUTH_LOGS"
dataset = "authhero_logs"
  1. 创建 API 键数字 :

创建 Cloudflare API 令牌 Account Analytics: Read 允许查询日志.

配置

interface AnalyticsEngineLogsAdapterConfig {
  // Analytics Engine dataset binding (for Workers)
  analyticsEngineBinding?: AnalyticsEngineDataset;

  // Cloudflare account ID (required for SQL queries)
  accountId: string;

  // API token with Analytics Engine read permission
  apiToken: string;

  // Dataset name (default: "authhero_logs")
  dataset?: string;

  // HTTP timeout in ms (default: 30000)
  timeout?: number;
}

使用量

import createAdapters, {
  createAnalyticsEngineLogsAdapter,
} from "@authhero/cloudflare-adapter";

// Option 1: Use via createAdapters
const adapters = createAdapters({
  zoneId: "your-zone-id",
  authKey: "your-api-key",
  authEmail: "your-email",
  customDomainAdapter: yourDbAdapter,

  analyticsEngineLogs: {
    analyticsEngineBinding: env.AUTH_LOGS,
    accountId: env.CLOUDFLARE_ACCOUNT_ID,
    apiToken: env.ANALYTICS_ENGINE_API_TOKEN,
    dataset: "authhero_logs",
  },
});

// Option 2: Use adapter directly
const logsAdapter = createAnalyticsEngineLogsAdapter({
  analyticsEngineBinding: env.AUTH_LOGS,
  accountId: env.CLOUDFLARE_ACCOUNT_ID,
  apiToken: env.ANALYTICS_ENGINE_API_TOKEN,
});

工人示例

interface Env {
  AUTH_LOGS: AnalyticsEngineDataset;
  CLOUDFLARE_ACCOUNT_ID: string;
  ANALYTICS_ENGINE_API_TOKEN: string;
}

export default {
  async fetch(request: Request, env: Env) {
    const { logs } = createAdapters({
      // ... other config
      analyticsEngineLogs: {
        analyticsEngineBinding: env.AUTH_LOGS,
        accountId: env.CLOUDFLARE_ACCOUNT_ID,
        apiToken: env.ANALYTICS_ENGINE_API_TOKEN,
      },
    });

    // Write a log (fire-and-forget, no await needed)
    await logs.create("tenant-123", {
      type: "s",
      date: new Date().toISOString(),
      ip: request.headers.get("cf-connecting-ip") || "",
      user_agent: request.headers.get("user-agent") || "",
      isMobile: false,
      user_id: "user-456",
      description: "User logged in",
    });

    // Query logs
    const recentLogs = await logs.list("tenant-123", {
      per_page: 50,
      q: "type:s",
    });

    return new Response("OK");
  },
};

通过模式

在使用核心的其他日志适配器旁使用分析引擎 createPassthroughAdapter 工具栏 :

import { createPassthroughAdapter } from "@authhero/adapter-interfaces";
import { createAnalyticsEngineLogsAdapter } from "@authhero/cloudflare-adapter";

// Primary adapter (e.g., database)
const databaseAdapter = createDatabaseLogsAdapter();

// Analytics Engine adapter for write syncing
const analyticsEngineAdapter = createAnalyticsEngineLogsAdapter({
  analyticsEngineBinding: env.AUTH_LOGS,
  accountId: env.CLOUDFLARE_ACCOUNT_ID,
  apiToken: env.ANALYTICS_ENGINE_API_TOKEN,
});

// Create passthrough adapter - writes to both, reads from primary
const logsAdapter = createPassthroughAdapter({
  primary: databaseAdapter,
  secondaries: [
    {
      adapter: { create: analyticsEngineAdapter.create },
      onError: (err) => console.error("Analytics sync failed:", err),
    },
  ],
});

// logs.create() writes to both adapters (database first, then Analytics Engine)
// logs.get() and logs.list() read from database only

数据Schema

分析引擎存储日志, 使用blob和双字段 :

外地类型说明
块1字符串日志( d)
blob2 (中文(简体) )字符串租户( d)
blob3 (中文(简体) )字符串类型(例如“s”、“f”)
blob4 (中文(简体) )字符串日期( ISO 字符串)
blob5 (中文(简体) )字符串说明
块6字符串页:1
blob7 (中文(简体) )字符串用户代理( a)
blob8-18 (中文(简体) )字符串用户 id,连接,客户端 id等.
blob19-20 (中文(简体) )字符串JSON 字符串( 细节、 认证 客户端)
双倍1编号移动 (0 或 1)
双倍2编号时间戳( 时间戳)
指数1字符串租户 id(用于高效过滤)

使用 SQL API 查询

# List recent logs for a tenant
curl "https://api.cloudflare.com/client/v4/accounts/{account_id}/analytics_engine/sql" \
  -H "Authorization: Bearer $API_TOKEN" \
  -d "SELECT * FROM authhero_logs WHERE index1 = 'tenant-123' ORDER BY timestamp DESC LIMIT 50"

# Count logins by type
curl "https://api.cloudflare.com/client/v4/accounts/{account_id}/analytics_engine/sql" \
  -H "Authorization: Bearer $API_TOKEN" \
  -d "SELECT blob3 as type, count() as count FROM authhero_logs WHERE index1 = 'tenant-123' GROUP BY blob3"

分析引擎)

createAnalyticsEngineOutboxMetricsSink 转动authhero的出箱中继参数 进入分析引擎数据点,所以死字母和重试后置是 可查询,而不是只出现在 console 输出.

设置

  1. 添加装订在 wrangler.toml数字 :
[[analytics_engine_datasets]]
binding = "OUTBOX_METRICS"
dataset = "authhero_outbox_metrics"
  1. 把水槽传到两个接力道上—— init() (按请求提供) 财务报告和审定财务报表 runOutboxRelay() (牛排排声):
import { createAnalyticsEngineOutboxMetricsSink } from "@authhero/cloudflare-adapter";
import { init, runOutboxRelay } from "authhero";

const metrics = createAnalyticsEngineOutboxMetricsSink({
  analyticsEngineBinding: env.OUTBOX_METRICS,
});

const { app } = init({ dataAdapter, outbox: { enabled: true, metrics } });

// in scheduled():
await runOutboxRelay({ dataAdapter, issuer: env.ISSUER, metrics });

无 analyticsEngineBinding 水槽是无声的,所以同样的接线 从事当地的脱衣和测试工作.

数据Schema

外地类型说明
块1字符串参数名称 (outbox_events_processed_total, (中文(简体) ), outbox_events_dead_lettered_total, (中文(简体) ), outbox_retry_delay_seconds(中文(简体) )
blob2 (中文(简体) )字符串租户( d)
blob3 (中文(简体) )字符串事件类型
blob4 (中文(简体) )字符串来源(request 或者说 cron(中文(简体) )
blob5 (中文(简体) )字符串目的地(仅交付失败)
块6字符串出错( 仅发送失败)
双倍1编号价值 - 1 计数器,以秒计重试延迟 outbox_retry_delay_seconds
双倍2编号重新计算事件( c)
双相 3编号时间戳( 时间戳)
指数1字符串租户 id(用于高效过滤)

分析引擎样本排在负载下,所以重量计数器由 _sample_interval 获取真实总数:

# Dead-lettered events per tenant
curl "https://api.cloudflare.com/client/v4/accounts/{account_id}/analytics_engine/sql" \
  -H "Authorization: Bearer $API_TOKEN" \
  -d "SELECT index1 as tenant, sum(double1 * _sample_interval) as dead_lettered FROM authhero_outbox_metrics WHERE blob1 = 'outbox_events_dead_lettered_total' GROUP BY index1"

地理适应器

Cloudflare Geo适配器从Cloudflare的自动请求头取出地理位置信息. 这用于用位置数据来丰富认证日志.

特征

  • 零纬度: Cloudflare 已经提供的用户头
  • 没有 API 呼叫: 不需要外部服务或数据库
  • 重大退化: 仅具有国家代码或完整位置数据的工作
  • 免费: Cloudflare自由计划中所有可用的功能

Cloudflare 设置

地理适配器需要启用特定的 Cloudflare 设置:

1. 启用 IP 地理定位(需要)

这提供了 cf-ipcountry 上面只有国家代码.

  1. 去你的云花仪表板
  2. 导航到 网络 设置
  3. 启用 IP 地理位置

这提供了包括城市,坐标,时区等全部位置数据.

  1. 去你的云花仪表板
  2. 导航到 规则 > 翻译: 转换规则 > 翻译: 管理变换
  3. 启用 添加访客位置头

这是一个 自由特性 所有Cloudflare计划中都有.

配置

地球适配器在创建Cloudflare适配器时自动包含. 信头按请求时间通过 getGeoInfo(headers)数字 :

import createAdapters from "@authhero/cloudflare-adapter";

// Create adapters once at startup
const adapters = createAdapters({
  // ... other config
});

// The geo adapter is always available
// Headers are passed when calling getGeoInfo
const headers = Object.fromEntries(request.headers);
const geoInfo = await adapters.geo.getGeoInfo(headers);

与 AuthHero 一起使用时,会自动从日志帮助器中的Hono上下文中取出标题.

已使用云旗信头

页眉说明示例可用性
cf-ipcountry2个字母的ISO国家代码US总是( 启用 IP 地理定位)
cf-ipcity城市名称San Francisco与管理变革
cf-iplatitude纬度坐标37.7749与管理变革
cf-iplongitude经度坐标-122.4194与管理变革
cf-timezoneIANA 时区标识符America/Los_Angeles与管理变革
cf-ipcontinent2个字母的大陆代码NA与管理变革

可用管理变换( 目前没有绘制) 的附加信头 :

  • cf-region区域名称
  • cf-region-code: 区域代码
  • cf-metro-code: 地铁代码
  • cf-postal-code: 邮政编码

响应格式

interface GeoInfo {
  country_code: string; // "US" - always available
  city_name: string; // "San Francisco" or "" if not available
  latitude: string; // "37.7749" or "" if not available
  longitude: string; // "-122.4194" or "" if not available
  time_zone: string; // "America/Los_Angeles" or "" if not available
  continent_code: string; // "NA" or "" if not available
}

只启用 IP 地理定位 :

{
  "country_code": "US",
  "city_name": "",
  "latitude": "",
  "longitude": "",
  "time_zone": "",
  "continent_code": ""
}

启用“ 添加访问者位置头” 管理变换:

{
  "country_code": "US",
  "city_name": "San Francisco",
  "latitude": "37.7749",
  "longitude": "-122.4194",
  "time_zone": "America/Los_Angeles",
  "continent_code": "NA"
}

与 Auth Hero 合并

在 AuthHero 中配置时,地理适配器会自动丰富认证日志. 日志助手会自动从 Hono 上下文中提取标题 :

import createAdapters from "@authhero/cloudflare-adapter";

const cloudflareAdapters = createAdapters({
  // ... other config
});

const dataAdapter = {
  ...yourDatabaseAdapter,
  geo: cloudflareAdapters.geo, // Add geo adapter
};

日志将自动包含 location_info数字 :

{
  "type": "s",
  "date": "2025-11-28T12:00:00.000Z",
  "location_info": {
    "country_code": "US",
    "city_name": "San Francisco",
    "latitude": "37.7749",
    "longitude": "-122.4194",
    "time_zone": "America/Los_Angeles",
    "continent_code": "NA"
  }
}

替代: IP 地理位置数据库

如果您没有使用 Cloudflare 或者需要更详细的位置数据, 您可以执行自定义 GeoAdapter 使用 MaxMind GeoIP 等 IP 地理定位数据库 :

import maxmind from "maxmind";
import { GeoAdapter, GeoInfo } from "@authhero/adapter-interfaces";

class MaxMindGeoAdapter implements GeoAdapter {
  private reader: maxmind.Reader<maxmind.CityResponse>;

  private constructor(reader: maxmind.Reader<maxmind.CityResponse>) {
    this.reader = reader;
  }

  static async create(databasePath: string): Promise<MaxMindGeoAdapter> {
    const reader = await maxmind.open<maxmind.CityResponse>(databasePath);
    return new MaxMindGeoAdapter(reader);
  }

  async getGeoInfo(headers: Record<string, string>): Promise<GeoInfo | null> {
    // Extract IP from headers (e.g., x-forwarded-for, cf-connecting-ip)
    const ip =
      headers["cf-connecting-ip"] ||
      headers["x-forwarded-for"]?.split(",")[0]?.trim() ||
      headers["x-real-ip"];

    if (!ip) return null;

    const lookup = this.reader.get(ip);

    if (!lookup) return null;

    return {
      country_code: lookup.country?.iso_code || "",
      city_name: lookup.city?.names?.en || "",
      latitude: lookup.location?.latitude?.toString() || "",
      longitude: lookup.location?.longitude?.toString() || "",
      time_zone: lookup.location?.time_zone || "",
      continent_code: lookup.continent?.code || "",
    };
  }
}

// Usage:
const geoAdapter = await MaxMindGeoAdapter.create(
  "/path/to/GeoLite2-City.mmdb",
);

对知识产权数据库的考虑数字 :

  • 需要数据库下载和定期更新
  • 检查的额外延迟(一般为1至5米)
  • 可能需要许可证费
  • 在任何环境中工作,而不仅仅是边缘平台

环境变量

建议的环境变量:

# Custom Domains
CLOUDFLARE_ZONE_ID=your_zone_id
CLOUDFLARE_AUTH_KEY=your_api_key
CLOUDFLARE_AUTH_EMAIL=your_email

# R2 SQL Logs (optional)
PIPELINE_ENDPOINT=https://your-stream-id.ingest.cloudflare.com
R2_SQL_AUTH_TOKEN=your_r2_sql_token
R2_WAREHOUSE_NAME=your_warehouse_name

类型脚本

该包包括了TypeScript定义. 视需要导入类型:

import type {
  CloudflareConfig,
  CloudflareAdapters,
  R2SQLLogsAdapterConfig,
} from "@authhero/cloudflare-adapter";

代码执行器

对于用户授权的代码钩(Actions), @authhero/cloudflare-adapter 2个代码执行器 根据您想要如何部署用户代码选择一个 :

WorkerLoaderCodeExecutor ——有活力劳动者

根据需要从内幕密码中抽出孤立的工人 装入器装订。没有单独的部署步骤——存储在您 actions编号 :hookCode 表格被装入每个钩子引用的新鲜隔离(带有以散列为基础的缓存,因此同一代码保持温暖).

import { WorkerLoaderCodeExecutor } from "@authhero/cloudflare-adapter";
import { init } from "authhero";

// Requires a worker_loaders binding in wrangler.toml:
// [[worker_loaders]]
// binding = "LOADER"

const codeExecutor = new WorkerLoaderCodeExecutor({
  loader: env.LOADER,
});

const { app } = init({ dataAdapter, codeExecutor });

DispatchNamespaceCodeExecutor - 平台工人组织

Invokes 已作为单独脚本预先部署的用户员工 发送命名空间执行者 deploy() 方法通过 Cloudflare API 上传脚本; execute() 通过命名空间绑定来引用它.

import { DispatchNamespaceCodeExecutor } from "@authhero/cloudflare-adapter";
import { init } from "authhero";

// Requires a dispatch_namespaces binding in wrangler.toml:
// [[dispatch_namespaces]]
// binding = "DISPATCHER"
// namespace = "authhero-hooks"

const codeExecutor = new DispatchNamespaceCodeExecutor({
  accountId: env.CF_ACCOUNT_ID,
  apiToken: env.CF_API_TOKEN,
  dispatchNamespace: "authhero-hooks",
  dispatcher: env.DISPATCHER,
});

const { app } = init({ dataAdapter, codeExecutor });

以前导出为 CloudflareCodeExecutor 从 authhero 财务报告和审定财务报表 @authhero/cloudflare-adapter 软件包。 该名称仍作为被贬值的别名被再出口 DispatchNamespaceCodeExecutor 将在下一个大赛中被淘汰.

见 钩子指南 详细情况.

许可证

麻省理工学院

版本与发布记录

@authhero/cloudflare-adapter 共发布 255 个版本,首次发布于 2025/03/04;过去 12 个月发布了 204 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
4.2.0latest2026/11/054 天前
4.1.22026/11/045 天前
4.1.12026/11/036 天前
4.1.02026/10/3010 天前
4.0.02026/10/3011 天前
3.4.02026/10/2911 天前

关于 @authhero/cloudflare-adapter 的常见问题

@authhero/cloudflare-adapter 是什么?

为AuthHero提供Cloudflare专用适配器,提供与Cloudflare服务的集成.

如何安装 @authhero/cloudflare-adapter?

在项目目录运行 npm install @authhero/cloudflare-adapter,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:hono(^4.12.30)、@hono/zod-openapi(^1.4.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@authhero/cloudflare-adapter 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@authhero/cloudflare-adapter 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@authhero/cloudflare-adapter 可以商用吗?

@authhero/cloudflare-adapter 使用 AGPL-3.0-only 许可。最严格的 Copyleft:除分发外,通过网络向用户提供基于它的服务也需要开源对应源码。闭源 SaaS 使用前务必评估。以上为概括,不构成法律意见,请以许可原文为准。

@authhero/cloudflare-adapter 的下载量有多少?

根据 npm 官方下载统计,@authhero/cloudflare-adapter 在 2026/10/07 – 2026/11/05 这 30 天内被下载 1,716 次,日均约 57 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@authhero/cloudflare-adapter 还在维护吗?

最新版本 4.2.0 发布于 2026/11/05(4 天前);至今共发布 255 个版本,其中过去 12 个月发布了 204 个;首次发布于 2025/03/04。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。