@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 格式存储的日志的查询接口
先决条件
- 创建 R2 桶并启用 R2 数据目录数字 :
npx wrangler r2 bucket create my-authhero-logs
npx wrangler r2 bucket catalog enable my-authhero-logs
注意输出中的"Warehouse"名称 - 你以后需要它.
- 创建 API 令牌
在云花板上:
- 转到 R2 对象存储
- 选择“ 管理 API 令牌 ”
- 使用管理员读取和写入权限创建一个令牌
- 保存符号值
- 创建计划文件 (单位:千美元)
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 }
]
}
- 创建管道数字 :
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 (冰堡) (英语) |
| 最佳服务 | 实时分析, 最近的日志 | 长期储存、遵守 |
| 定价 | 可自由分级 | 每个存储+查询付费 |
先决条件
- 创建分析引擎数据集数字 :
配置在 wrangler.toml数字 :
[[analytics_engine_datasets]]
binding = "AUTH_LOGS"
dataset = "authhero_logs"
- 创建 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 输出.
设置
- 添加装订在
wrangler.toml数字 :
[[analytics_engine_datasets]]
binding = "OUTBOX_METRICS"
dataset = "authhero_outbox_metrics"
- 把水槽传到两个接力道上——
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 上面只有国家代码.
- 去你的云花仪表板
- 导航到 网络 设置
- 启用 IP 地理位置
2. 启用“ 添加访问者位置头” 管理变换( 建议)
这提供了包括城市,坐标,时区等全部位置数据.
- 去你的云花仪表板
- 导航到 规则 > 翻译: 转换规则 > 翻译: 管理变换
- 启用 添加访客位置头
这是一个 自由特性 所有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-ipcountry | 2个字母的ISO国家代码 | US | 总是( 启用 IP 地理定位) |
cf-ipcity | 城市名称 | San Francisco | 与管理变革 |
cf-iplatitude | 纬度坐标 | 37.7749 | 与管理变革 |
cf-iplongitude | 经度坐标 | -122.4194 | 与管理变革 |
cf-timezone | IANA 时区标识符 | America/Los_Angeles | 与管理变革 |
cf-ipcontinent | 2个字母的大陆代码 | 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将在下一个大赛中被淘汰.
见 钩子指南 详细情况.
相关文档
许可证
麻省理工学院