# @activescott/auth-adapter-react-router 中文文档

规范地址：https://npmcn.com/package/%40activescott/auth-adapter-react-router/

版本：3\.1\.0
npm 元数据更新时间：2026-10-19T01:37:29.620Z
中文译文更新时间：2026-11-06T01:44:30.937Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40activescott/auth-adapter-react-router
原文对照：https://npmcn.com/package/%40activescott/auth-adapter-react-router/?lang=original
项目主页：https://github.com/activescott/auth#readme
源码仓库：https://github.com/activescott/auth

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：310 kB，131 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：0 个
- peer 依赖：react \>=18，react-router ^7\.0\.0 \|\| ^8\.0\.0，@activescott/auth ^5\.2\.0
- 首次发布：2026-03-16T19:01:06.967Z
- 最新版本发布：2026-10-19T01:37:29.266Z
- 近 30 天下载量：7139（2026-10-05 至 2026-11-03，npm 官方下载统计）
- 已发布版本数：21（近 12 个月 21 个）

## 中文简介

@ activescott/ auth 的回放路由器适配器

## 安装

```sh
npm install @activescott/auth-adapter-react-router
```

也可以使用：`pnpm add @activescott/auth-adapter-react-router`、`yarn add @activescott/auth-adapter-react-router`、`bun add @activescott/auth-adapter-react-router`

## README

# @activescott/auth-adapter-反应-路由器

[![npm version](https://img.shields.io/npm/v/@activescott/auth-adapter-react-router.svg)](https://www.npmjs.com/package/@activescott/auth-adapter-react-router) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

反应路由器适配器(v7和v8) [`@activescott/auth`](https://www.npmjs.com/package/@activescott/auth)组合框架不可知性 `Auth` 处理器中读取/写入标准的类 `Request` 财务报告和审定财务报表 `Response` 对象 – 精确的 React 路由器加载器和动作返回什么 .

适配器没有从 `react-router`; 它只会说抓取 `Request`编号 :`Response`,所以同样的构建在两个主要版本上. 这对管理员的页面来说也是一样 `Link`。 。 。 .

用于生产 [frumblefeed.com (英语)](https://ramblefeed.com/) 财务报告和审定财务报表 [(原始内容存档于2018-10-21). dinkerbellbot.com](https://tinkerbellbot.com/)。 。 。 .

## 安装

```bash
npm install @activescott/auth @activescott/auth-provider-email @activescott/auth-adapter-react-router
```

## 使用量

```ts
// app/lib/auth.server.ts
import { Auth } from "@activescott/auth"
import { EmailProvider } from "@activescott/auth-provider-email"
import { createAuthHandlers } from "@activescott/auth-adapter-react-router"

export const auth = new Auth({/* ...session, stores, providers... */})

export const { handleAuth, getSession, requireAuth, optionalAuth, logout } =
  createAuthHandlers(auth, {
    successRedirect: "/",
    errorRedirect: "/login",
    loginUrl: "/login",
  })
```

`errorRedirect` 作为字符串附件 `?error=<code>` 该路径将丢弃提交表单的查询。 如果您的登录页面在查询中保持状态—— a `?via=sms` 选项卡选择,例如——在错误的标签上会回答一个失败的代码。 函数表单接收失败的请求, 所以核心的 `buildReturnUrl` 可以将浏览器发回它从 :

```ts
import { buildReturnUrl } from "@activescott/auth"

errorRedirect: (error, request) =>
  buildReturnUrl(request, { error: error.code })
```

然后在 `app/routes/auth.$provider.$action.tsx` 处理每个提供者的 HTTP 端点 :

```tsx
import { handleAuth } from "~/lib/auth.server"
import type { Route } from "./+types/auth.$provider.$action"

export const loader = ({ request }: Route.LoaderArgs) => handleAuth({ request })
export const action = ({ request }: Route.ActionArgs) => handleAuth({ request })
```

这个文件覆盖 `/auth/<provider>/<action>` 每个注册提供者,例如:. `POST /auth/email/initiate` (您在此登录表单), `GET /auth/email/verify?...` (魔法链接确认页), `POST /auth/email/verify` (链接救赎或代码条目), `/auth/sms/...`, (中文(简体) ), `/auth/passkey/...`等 (中文(简体) ). `handleAuth` 发送到右侧提供者, 运行 `verify` 或者说 `initiate`,设置/清除会话 cookie,并返回方向调整——或通过提供者制作的一页(如魔法链接确认页面).

该路线没有组件,使它成为一个资源路线,反应-路由器运行它 `Origin` 只检查文档和单向动作。 这么说吧 `handleAuth` 运行检查本身:带有 `Origin` 这不是这个应用程序的400, 一个请求没有 `Origin` 过关(如反应 -- -- 路由器所做的那样),而GET则未受影响。 登录路由是资源路由 出于同样的原因,所以 `logout` 接受请求并运行相同的检查 :

```tsx
import { logout } from "~/lib/auth.server"
import type { Route } from "./+types/logout"

export function action({ request }: Route.ActionArgs) {
  return logout(request, "/")
}
```

比较 `request.url`,因此在终止 TLS 的代理之后,应用程序仍然必须信任代理(`app.set("trust proxy", 1)` ),或者浏览器的每个帖子看起来都是跨出源的.

保护任何装入器 `requireAuth(request)`数字 :

```tsx
export async function loader({ request }: Route.LoaderArgs) {
  const user = await requireAuth(request) // redirects to /login if no session
  return { user }
}
```

## 按要求进行的检查

Apps通常有一个规则,规定除了"饼干核实"之外,谁可以举行一个会话:只批准账户,而不是你今天上午所封的账户. `onSessionVerified` 每个会话运行 `getSession`, (中文(简体) ), `requireAuth` 财务报告和审定财务报表 `optionalAuth` 核实, 之后 `mapUser`返回或投掷 `Response` 请求将随它而反弹。不返回任何结果,会话将持续到您的装载器上:

```ts
export const { requireAuth, optionalAuth, clearSessionCookie, logout } =
  createAuthHandlers<AppUser>(auth, {
    mapUser,
    onSessionVerified: ({ user }) => {
      if (user.status === "BLOCKED") {
        return redirect("/login", {
          headers: { "Set-Cookie": auth.destroySessionCookie() },
        })
      }
      if (user.status === "PENDING") return redirect("/waitlist")
    },
  })
```

代替包装软件 `requireAuth` 重新读取用户并按他们找到的东西行事,因为它运行在 `optionalAuth` 财务报告和审定财务报表 `getSession` 也可以免费获得同样的规则。 设定 `session: { cacheTtlMs: 0 }` 编辑 `Auth` 与它相接:钩子 `user` 不管怎么样 `verifySession` 返回,默认时间为两分钟.

它不运行 `renewSessionCookie` 或者说 `refreshSessionCookie`,它重新为会话发行饼干,一个已经接受的加载器.

`clearSessionCookie()` 返回时 `Set-Cookie` 过期会话 cookie 的值,因为您需要标题而不是方向 `logout` 把它包起来.

## 滚动会议

届会结束 `maxAge` 在发布后,无论访问者是否仍在使用该应用程序。 设定 `session.renewAfter` 打电话 `renewSessionCookie` 由您的根加载器在饼干过后再发行

```ts
export const { renewSessionCookie, ...handlers } = createAuthHandlers(auth, {
  session: { renewAfter: "7d" }, // well inside the "30d" maxAge
})

// app/root.tsx
export async function loader({ request }: Route.LoaderArgs) {
  const user = await optionalAuth(request)
  const loaderData = { user }

  const cookie = user && (await renewSessionCookie(request, user))
  return cookie
    ? data(loaderData, { headers: { "Set-Cookie": cookie } })
    : loaderData
}
```

`renewSessionCookie` 当会话仍然新鲜时返回为无效,所以常见的大小写没有标题。 如果你不配置,它就会扔出去 `session.renewAfter`。要更新会话,是因为用户自己的数据发生了变化(如一个新的手柄),而不是因为它是旧的,使用 `refreshSessionCookie`,无条件重发.

## API 密码

| 导出 | 目的 |
| --- | --- |
| `createAuthHandlers` | 回返 `{ handleAuth, getSession, requireAuth, optionalAuth, renewSessionCookie, refreshSessionCookie, clearSessionCookie, logout }`。 。 。 . |
| `createAuthPageLoaders` | 回返 `{ signInLoader, profileAuthLoader, listSignInMethods }`。见 [签名和简介页面](https://npmcn.com/package/%40activescott/auth-adapter-react-router/#readme-sign-in-and-profile-pages)。 。 。 . |
| 钩子(来自 `./client`(中文(简体) ) | `useTurnstile`, (中文(简体) ), `usePasskeySignIn`, (中文(简体) ), `useRegisterPasskey`, (中文(简体) ), `useOtpAutoSubmit`, (中文(简体) ), `usePreservedInput`。 。 。 . |
| `createAdminHandlers` (从) `./admin`(中文(简体) ) | 回返 `{ requireAdmin, adminUsersLoader, adminConfigLoader }`。 。 。 . |
| `AdminUsersPage`, (中文(简体) ), `AdminConfigPage` | 管理页面,从 `./admin`。 。 。 . |
| `ProfilePage` (从) `./profile`(中文(简体) ) | 简介页,以及 `AccountSummary`, (中文(简体) ), `SignInMethods`, (中文(简体) ), `Passkeys` 分别。 见 [简介页](https://npmcn.com/package/%40activescott/auth-adapter-react-router/#readme-profile-page)。 。 。 . |

登录页面不需要自己的动作:将电子邮件表直接寄到 `/auth/email/initiate` (提供方以 `?sent=1`)和代码表 `/auth/email/verify`。 。 。 .

`createAuthHandlers<TUser>` 在应用程序的用户类型上通用。 通过 a `mapUser` 键入 `requireAuth<TUser>` 编号 : `optionalAuth<TUser>` 而不是赤裸的 `AuthUser`。 。 。 .

## 签名和简介页面

适配器将一个登录页和配置页的登录方法部分的逻辑传递给您,然后将标记留给您. 加载器运行在服务器上,并读取供应商在回程时放入查询字符串的内容;钩子运行在浏览器中. 简介页的标记船也作为组件:见 [简介页](https://npmcn.com/package/%40activescott/auth-adapter-react-router/#readme-profile-page)。 。 。 .

```ts
// app/lib/auth.server.ts
import { createAuthPageLoaders } from "@activescott/auth-adapter-react-router"
import { listPasskeys } from "@activescott/auth-provider-passkey" // only if you use passkeys

export const { signInLoader, profileAuthLoader } = createAuthPageLoaders(auth, {
  turnstileSiteKey: process.env.TURNSTILE_SITE_KEY,
  listPasskeys,
  errorMessages: { blocked: "Your account has been blocked." },
})
```

`signInLoader(request)` 返回时 `{ via, sent, error, errorCode, redirectTo, formToken, turnstileSiteKey }`: 哪些提供者的表格可以显示, 信件是否出出, 信件用于 `?error=`,同一来源 `redirectTo` 或无效,签名的表格表示滥用检查的预期值 `FORM_TOKEN_FIELD`。 。 。 . `profileAuthLoader(userId, request)` 返回时 `{ identities, passkeys, linkFlow, removal }`时 `linkFlow` 是添加- a- sign- in- 方法流: 打开的窗体(`?add=`, (中文(简体) ), `sent`, (中文(简体) ), `linked`, (中文(简体) ), `merged`,以及 `conflict`,其 `link-merge` 赎回合并票 `IDENTITY_CONFLICT`。它从 `?provider=`,则 `?add=`,所以将 `?add=` 在验证步骤中 `redirectTo`。 。 。 . `removal` 是删除按钮的结果:提供者(`?removed=`,或 `?provider=` 与 `?removeError=`),是否通过,和拒绝的信息. `errorMessages` 添加库所不知道的代码,如起动门's,并重写任何它所做的;两个加载器也接受每个调用.

钩子在那边 `./client` 子路径和需要 React 而非 React 路由器 :

| 钩子 | 对于 |
| --- | --- |
| `useTurnstile(siteKey)` | 将旋转部件渲染成 `containerRef` 和报告 `ready`; 禁用提交到那时。 报告 `"failed"` 20秒后,没有标志. |
| `usePasskeySignIn({ client, redirectTo })` | `signIn` 密码按钮; 全页负载 `redirectTo` 在成功方面. `autofill: true` 添加有条件的UI. |
| `useRegisterPasskey({ client, onRegistered })` | `register` 用于“添加密码”;通过 `useRevalidator().revalidate` 作为 `onRegistered`。 。 。 . |
| `useOtpAutoSubmit(length)` | `inputProps` 用于在最后一个数字降落时提交表单的代码字段(包含自动填充属性). |
| `usePreservedInput(key)` | 在会话Storage中,保持打入的地址或号码,通过认证路线进行往返. |

钥匙钩拿 `createPasskeyClient()` 从 `@activescott/auth-provider-passkey/browser` 作为 `client`,因此没有密码的应用程序从不安装WebAuthn库. 上山时,他们叫客户的 `prepareSignIn` 或者说 `prepareRegistration`Safari拒绝在等待取回后开始的密码仪式。 一个Turnstile标志比它看起来更重要:一个没有一张的表格被屏蔽. 核心发布方式 `BOT_CHECK_INCOMPLETE` 以可重试错误回答; 年龄较长 `@activescott/auth` 仍然回答它像一个成功的发送, 和所有其他bot检查拒绝保持不透明 无论是哪种方式。 门提交于 `ready`。 。 。 .

[`examples/react-router`](https://github.com/activescott/auth/tree/main/examples/react-router) 使用其中的全部: `app/routes/login.tsx` 财务报告和审定财务报表 `app/routes/dashboard.tsx`。 。 。 .

## 简介页

每个应用程序都有一个简介页,所以适配器在 `./profile` 子路径. `ProfilePage` 制作账户摘要、登录方法和密码 `profileAuthLoader` 返回.

```tsx
// app/routes/profile.tsx
import { Link, useRevalidator } from "react-router"
import { ProfilePage } from "@activescott/auth-adapter-react-router/profile"
import { profileAuthLoader, requireAuth } from "~/lib/auth.server"
import { passkeys } from "~/lib/passkeys"

export async function loader({ request }: Route.LoaderArgs) {
  const user = await requireAuth(request)
  return {
    email: user.email,
    memberSince: user.createdAt.toISOString(),
    ...(await profileAuthLoader(user.id, request)),
  }
}

export default function Profile({ loaderData }: Route.ComponentProps) {
  const revalidator = useRevalidator()
  return (
    <ProfilePage
      {...loaderData}
      addMethods={[
        { provider: "email" },
        { provider: "sms", callingCode: "+1" },
      ]}
      passkeyClient={passkeys}
      onPasskeyRegistered={revalidator.revalidate}
      linkComponent={Link}
    />
  )
}
```

`addMethods` 是页面提供要添加的内容, 按链接显示的顺序; 它默认不提供任何东西, 除非条目设定, 并且将账户已经签名的提供者丢入 `allowMultiple`。 。 。 . `callingCode` 使球场采用国家编号并提交完整的E.164 1. `allowMerge` 转动 `IDENTITY_CONFLICT` 输入一个合并两个账户的提议,而不是一个错误,所以它只设定在您 `UserStore.onMerge` 合并. `allowRemove` 在每个登录方式和密码上设置一个删除按钮;它会张贴到核心的 `/auth/{provider}/unlink` (单位:千美元)`@activescott/auth` 第5.9.0或以后),拒绝用户与用户签入的方法和最后一个可以收回账户的方法。 过 `removal` 从加载器上,所以页面报告结果.

带有自己的部分的申请书使区块按任何顺序和区块之间的任何顺序直接:

```tsx
<AccountSummary email={user.email} entries={[{ label: "Handle", value: user.handle }]} />
<HandleSection handle={user.handle} />
<SignInMethods identities={identities} linkFlow={linkFlow} addMethods={addMethods} linkComponent={Link} />
<Passkeys passkeys={passkeys} client={passkeyClient} onRegistered={revalidator.revalidate} />
```

### 样式

每个街区 `classNames`,每个槽一个类 : `card`, (中文(简体) ), `cardBody`, (中文(简体) ), `cardTitle`, (中文(简体) ), `table`, (中文(简体) ), `th`, (中文(简体) ), `td`, (中文(简体) ), `field`, (中文(简体) ), `label`, (中文(简体) ), `input`, (中文(简体) ), `submitButton`, (中文(简体) ), `success` 和其余部分 `ProfileClassNames`。一个槽,你的名字会得到你的班级,没有内置的样式,因为内置的样式比它原本会与之竞争的级别要高;槽,你不会说保持平地内置的外观 `includeDefaultStyles={false}` 到处都是.

这意味着"半名地图"是"半作"一页",有34个档. 在"靴子"上,通过地图 包船代替:

```tsx
import {
  BOOTSTRAP_PROFILE_CLASS_NAMES,
  ProfilePage,
} from "@activescott/auth-adapter-react-router/profile"

;<ProfilePage {...loaderData} classNames={BOOTSTRAP_PROFILE_CLASS_NAMES} />
```

张开以更改一个位置并保留其余部分: `{ ...BOOTSTRAP_PROFILE_CLASS_NAMES, title: "fw-bold text-primary mb-4" }`输入 `Required<ProfileClassNames>`,所以一个后加的插槽必须在软件包构建之前给出一个类.

对于另一个框架,你自己写地图. 空字符串是您拥有的插槽, 但不想要上课, 即Bootstrap's的方式 `.table` 到达自有的单元格:它不添加属性就放弃了内置样式.

通知在加价中而不是在 `classNames`,因为一个班级不能增加一个班级:失败或谨慎带有 `role="alert"`,确认 `role="status"`,关于您输入的地址或代码的信息将绑定在该字段上 `aria-invalid` 财务报告和审定财务报表 `aria-describedby`。 。 。 .

区块导入回放,但没有从 `react-router`因此,链接通过可选 `linkComponent`;没有它,它们就是平地锚, 导航整个文件。 表格是简单的 `<form>` 元素在目的上: 添加- a- sign- in- method 流的每个步骤都是一个文件 POST , 认证路由用重定向回答, 也就是让流的状态活在 URL 中.

## 行政仪表板

仅读用户页面和配置页面,位于 `./admin` 子路径所以不使用它们的应用程序从不装入反应 :

```tsx
// app/lib/auth.server.ts
import { createAdminHandlers } from "@activescott/auth-adapter-react-router/admin"

export const { adminUsersLoader, adminConfigLoader } = createAdminHandlers(
  auth,
  {
    requireAuth,
    admins: process.env.AUTH_ADMIN_IDENTIFIERS,
  },
)

// app/routes/admin.users.tsx
import { Link } from "react-router"
import { AdminUsersPage } from "@activescott/auth-adapter-react-router/admin"

export const loader = ({ request }: Route.LoaderArgs) =>
  adminUsersLoader({ request })

export default function AdminUsers({ loaderData }: Route.ComponentProps) {
  return <AdminUsersPage data={loaderData} linkComponent={Link} />
}
```

用户页面需要 `UserStore.listUsers`,该选项是可选的,由应用程序执行;将您想要的任何内容作为额外的一列输入每个用户的 `metadata` 并用 `metadataColumns`。访问是电子邮件地址和电话号码的允许列表(`AUTH_ADMIN_IDENTIFIERS` (默认情况下),当未设置时,不会接纳任何人;非管理员得到404分.

完全通过 : [行政仪表板](https://github.com/activescott/auth#admin-dashboard)。 。 。 .

## E2e 代码回读

`createCaptureReadbackLoader`时 `./testing` subpath,是一个资源路由加载器,它把最后缴获的登录电子邮件或短消息交给您的e2e测试,这样他们就可以在没有收件箱或手机的情况下签名. 把运输工具包起来 `CaptureEmailTransport` 编号 : `CaptureSmsTransport` (来自每个供应商的) `/testing` 子路径)在同一试验模式旗下:

```ts
// app/routes/e2e.otp-code.tsx
import { createCaptureReadbackLoader } from "@activescott/auth-adapter-react-router/testing"

export const loader = createCaptureReadbackLoader({
  transports: { email: captureEmailTransport, sms: captureSmsTransport },
  enabled: process.env.E2E_TEST_MODE === "true",
  secret: process.env.E2E_MAGIC_LINK_SECRET,
})
```

测试呼叫 `GET /e2e/otp-code?email=...` 或者说 `?phone=...` 与秘密在一个 `x-e2e-secret` 头曰. 捕捉到的代码是现场记录: 路线回答一个赤裸的404,除非 `enabled` 没错 `true` 和密制的火柴 `enabled` 但没有秘密。 从不设定生产旗.

## 文档实例( E)

Full Docs 和一个带有 Playwright 测试的可运行的 React Router 框架- mode 实例在 monrepo 中直播 :

→ **[https://github.com/活塞斯科特/奥斯\*](https://github.com/activescott/auth*)\* 联合国**

## 许可证

麻省理工学院

## 常见问题

### @activescott/auth-adapter-react-router 是什么？

@ activescott/ auth 的回放路由器适配器

### 如何安装 @activescott/auth-adapter-react-router？

在项目目录运行 npm install @activescott/auth-adapter-react-router，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：react-router（^7\.0\.0 \|\| ^8\.0\.0）、@activescott/auth（^5\.2\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @activescott/auth-adapter-react-router 支持 TypeScript 吗？

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

### @activescott/auth-adapter-react-router 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @activescott/auth-adapter-react-router 可以商用吗？

@activescott/auth-adapter-react-router 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @activescott/auth-adapter-react-router 的下载量有多少？

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

### @activescott/auth-adapter-react-router 还在维护吗？

最新版本 3\.1\.0 发布于 2026/10/19（19 天前）；至今共发布 21 个版本，其中过去 12 个月发布了 21 个；首次发布于 2026/03/17。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

