@fastify/passport

中文文档
4.0.4发布于 2026/10/10MITTypeScriptCommonJS构建来源已验证近 30 天下载 30.6万

简单,无侵扰性的快速认证.

中文使用文档
文档目录22 节
  1. 状态
  2. 安装
  3. Google OAuth2 视频教程
  4. 示例
  5. 保护路线
  6. 登录的会话清理
  7. 差异 @fastify/secure-session 财务报告和审定财务报表 @fastify/session
  8. 会话序列化
  9. API 密码
  10. 初始化()
  11. 安全会议
  12. 认证( 战略: 字符串 QQ 策略 QQ (字符串 QQ 策略) ) [], 选项: 认证选项, 回调
  13. 授权( 策略: 字符串 QQ 策略 QQ (字符串 QQ 策略 ) [], 选项: 认证选项 = QQ, 回调
  14. 使用( 名称? : 字符串, 策略: 策略)
  15. 未使用( 名称: 字符串)
  16. 注册用户序列器( 序列器 ): (用户, 请求) QQ 承诺)
  17. 用户定义器( 定义器 :( 序列化用户, 请求) QQ 承诺)
  18. 请求# is 认证( )
  19. 请求# 是未经认证的 ()
  20. 使用类型脚本
  21. 使用多个实例
  22. 许可证

@ fastify/ 护照

CI NPM version neostandard javascript style

@fastify/passport 是一个端口 passport 为快速生态系统。 它允许您使用护照策略验证请求并保护快路!

状态

贝塔. @fastify/passport 仍是一个相对较新的项目。 可能与快递不相容 passport 部署和错误。 请报告任何问题,以便我们纠正!

安装

npm i @fastify/passport

Google OAuth2 视频教程

社区创造了这个快速的介绍 @fastify/passport数字 : Google OAuth2 Tutorial Passport

示例

import fastifyPassport from '@fastify/passport'
import fastifySecureSession from '@fastify/secure-session'

const server = fastify()
// set up secure sessions for @fastify/passport to store data in
server.register(fastifySecureSession, { key: fs.readFileSync(path.join(__dirname, 'secret-key')) })
// initialize @fastify/passport and connect it to the secure-session storage. Note: both of these plugins are mandatory.
server.register(fastifyPassport.initialize())
server.register(fastifyPassport.secureSession())

// register an example strategy for fastifyPassport to authenticate users using
fastifyPassport.use('test', new SomePassportStrategy()) // you'd probably use some passport strategy from npm here

// log users in with the strategy named "test": on success the user is stored in the session and redirected to /
server.post(
  '/login',
  { preValidation: fastifyPassport.authenticate('test', { successRedirect: '/', authInfo: false }) },
  () => {}
)

// require a login for a route: the session hook has already populated request.user for logged-in requests
server.get(
  '/',
  {
    preValidation: async (request, reply) => {
      if (!request.isAuthenticated()) return reply.redirect('/login')
    }
  },
  async () => 'hello world!'
)

server.listen()

或者, @fastify/session 也支持并工作在会话存储的框外. 举个例子:

import { Authenticator } from '@fastify/passport'
import fastifyCookie from '@fastify/cookie'
import fastifySession from '@fastify/session'

const server = fastify()

// setup an Authenticator instance which uses @fastify/session
const fastifyPassport = new Authenticator()

server.register(fastifyCookie)
server.register(fastifySession, { secret: 'secret with minimum length of 32 characters' })

// initialize @fastify/passport and connect it to the secure-session storage. Note: both of these plugins are mandatory.
server.register(fastifyPassport.initialize())
server.register(fastifyPassport.secureSession())

// register an example strategy for fastifyPassport to authenticate users using
fastifyPassport.use('test', new SomePassportStrategy()) // you'd probably use some passport strategy from npm here

保护路线

authenticate() 运行一个策略。 它不检查请求是否已经存在会话, 因此它是路径的右钩 执行 登录(登录路线和OAuth召回路线),错误的路线 需求 一个.

一次 secureSession() 已注册,每个包含登录会话的请求已经 request.user 在任何路线级的钩子运行之前,有人为你服务。 警卫保护路线在那,与 request.isAuthenticated()数字 :

const requireLogin = async (request, reply) => {
  if (!request.isAuthenticated()) {
    request.session.set('returnTo', request.url) // optional, see successReturnToOrRedirect
    return reply.redirect('/auth/login')
  }
}

// performs the login
server.get('/auth/login', { preValidation: fastifyPassport.authenticate('google') }, () => {})
server.get(
  '/auth/callback',
  { preValidation: fastifyPassport.authenticate('google', { successRedirect: '/' }) },
  () => {}
)

// requires a login
server.get('/', { preValidation: requireLogin }, async (request) => request.user)

采用重定向战略(任何OAuth/OIDC战略): passport-microsoft, (中文(简体) ), passport-google-oauth20, (中文(简体) ), passport-github2,.)在被保护的路由上产生无限重定向循环而不是出错,因为策略在请求中没有证书,因此重定向到身份提供者,提供者承认自己的会话,并立即重定向回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回调回

// DON'T: '/' bounces to the IdP and back forever, even for a logged-in user
server.get('/', { preValidation: fastifyPassport.authenticate('google') }, async (request) => request.user)

还注意到 authenticate('session') 不是警卫 内在会话战略 通过 当会话没有用户而非失败时 failureRedirect 永远不要起火, 和操作员运行 request.user 未设.

登录的会话清理

出于安全考虑,会话在登录后被清理. 您可以通过 :

  1. 包含 keepSessionInfo 执行护照时的真实选项 .authenticate 电话;
  2. 包含 keepSessionInfo 执行请求时的真实选项 .login 电话;
  3. 使用 clearSessionOnLogin (default: true) 财务报告和审定财务报表 clearSessionIgnoreFields (default: ['passport', 'session'])。 。 。 .

差异 @fastify/secure-session 财务报告和审定财务报表 @fastify/session

@fastify/secure-session 财务报告和审定财务报表 @fastify/session 是两个可加密/解密会话的会话插件。 主要的区别在于 @fastify/secure-session 使用无国籍方法,将整个会话存储在加密的饼干中,而 @fastify/session 在会话中使用状态化方法并将其存储在会话商店中.

会话序列化

在一个典型的网络应用程序中,用于认证用户的证书只有在用户登录进入时和之后才会被传送一次,因为有些数据存储在其会话中,才被视为登录. @fastify/passport 通过使用 @fastify/secure-session,并将用户对象序列化/去序化,使之与饼干引用的会话相接. @fastify/passport 无法在会话中存储丰富的对象类, 只保存 JSON 对象, 因此, 如果您想要从数据库中获取用户对象, 您必须注册序列器/ 删除器对, 并且只存储会话中的用户 ID .

// register a serializer that stores the user object's id in the session ...
fastifyPassport.registerUserSerializer(async (user, request) => user.id);

// ... and then a deserializer that will fetch that user from the database when a request with an id in the session arrives
fastifyPassport.registerUserDeserializer(async (id, request) => {
  return await User.findById(id);
});

API 密码

初始化()

钩子 必须添加设置 @fastify/passport 实验的钩子.

安全会议

钩子 必须添加设置 @fastify/passport与 @fastify/secure-session 在会话中存储认证.

认证( 战略: 字符串 QQ 策略 QQ (字符串 QQ 策略) ) [], 选项: 认证选项, 回调

返回认证请求的钩子,换句话说,验证用户,然后将其签入. authenticate 用作 preValidation 钩在特定的路线上像 /login。 。 。 .

将给定的战略(或策略)应用到收到的请求中,以认证请求. 战略通常在时间之前使用 .use,然后转至 .authenticate 以名为相. 如果认证成功,用户将在 request.user 并默认设立会话。 如果认证失败, 将发出未经授权的响应 .

战略或一系列战略也可作为实例来通过。 当您只打算对一个用户使用一次的临时策略, 并且不想注册到可用策略的全球列表时, 这样做是有用的 .

选项 :

  • session 在会话中保存登录状态,默认为 真实
  • successRedirect 成功登录后, 重定向到指定的 URL
  • successReturnToOrRedirect 成功登录后, 重定向到会话中存储的 URL returnTo 如果有的话,则使用给定的URL。 注意默认登录时会话已被清除, 因此 returnTo 必须保留:添加 'returnTo' 页:1 Authenticator是因为 clearSessionIgnoreFields,或通过 keepSessionInfo: true 此处(参见 登录的会话清理(中文(简体) )
  • successMessage 将成功消息存储到 req. session. messages, 或用作覆盖的字符串 成功的信息.
  • successFlash 用于闪存成功消息或用作闪存的字符串的真伪 成功信息(取代战略本身的任何信息).
  • failureRedirect 登录失败后, 重定向到给定的 URL
  • failureMessage 将失败消息存储到 req. session. messages, 或用作覆盖的字符串 失败信息.
  • failureFlash 用于闪存失败消息或用作闪存的字符串的真伪 失败信息(超过战略本身的任何信息).
  • assignProperty 将验证回调对象指定为给定属性
  • authInfo 通过 info 通过已注册的认证信息转换器返回策略的验证回调,并将结果存储在 request.authInfo,默认为 真实设置为 虚假 跳过此选项
  • failWithError 在失败的登录时, 丢出一个 AuthenticationError 而不是发送失败响应, 因此它会到达您的快速错误处理器
  • state 将任何提供的状态传递到策略中( 例如 Google Oauth)
  • keepSessionInfo 认证后保存现有会话属性的真伪

可选 callback 能够提供允许应用程序推翻处理认证尝试的默认方式。 召回的签名如下:

(request, reply, err | null, user | false, info?, (status | statuses)?) => Promise<void>

地点 request 财务报告和审定财务报表 reply 将设置为原始 FastifyRequest 财务报告和审定财务报表 FastifyReply 对象,以及 err 将设定为 null 在成功或成功的情况下 Error 对象,如果失败。 若为 err 没有 null 接下来 user, (中文(简体) ), info,以及 status 对象将是 undefined编辑 user 对象将在认证尝试成功时设定给认证的用户,或 false 否则.

可选 info 参数将会被传递, 包含由策略的验证回调提供的更多细节 - 这可以是关于成功认证的信息, 也可以是失败认证的质疑信息 .

可选 status 或者说 statuses 当认证失败时会通过参数 - 这可以是远程认证失败或类似的 HTTP 响应代码 .

fastify.get(
  '/',
  { preValidation: fastifyPassport.authenticate('test', { authInfo: false }) },
  async (request, reply, err, user, info, status) => {
    if (err !== null) {
      console.warn(err)
    } else if (user) {
      console.log(`Hello ${user.name}!`)
    }
  }
)

实例:

// create a request handler that uses the Facebook strategy
fastifyPassport.use(new FacebookStrategy('facebook', {
  // options for the Facebook strategy, see https://www.npmjs.com/package/passport-facebook
})))
fastifyPassport.authenticate('facebook');

// create a request handler to test against the strategy named local, and automatically redirect when it succeeds or fails
fastifyPassport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' });

// create a request handler that won't use any user information stored in the secure session
fastifyPassport.authenticate('basic', { session: false });

注意如果提供回调,则成为应用程序登录用户的责任,建立会话,并进行所期望的操作.

多重战略

@fastify/passport 支持以策略列表进行认证,并按顺序逐一进行,直到一个通过。 传出一系列策略名称到 authenticate 为此:

// somewhere before several strategies are registered
fastifyPassport.use('bearer', new BearerTokenStrategy())
fastifyPassport.use('basic', new BasicAuthStrategy())
fastifyPassport.use('google', new FancyGoogleStrategy())

// and then an `authenticate` call can test incoming requests against multiple strategies
fastify.get(
  '/',
  { preValidation: fastifyPassport.authenticate(['bearer', 'basic', 'google'], { authInfo: false }) },
  async (request, reply, err, user, info, status) => {
    if (err !== null) {
      console.warn(err)
    } else if (user) {
      console.log(`Hello ${user.name}!`)
    }
  }
)

请注意,重定向启动认证流的多种策略,如来自主要平台的OAuth2策略,不应在同一平台一起使用 authenticate 电话 这是因为 @fastify/passport 将按顺序运行策略,而第一个重定向策略将这样做,防止用户使用其他策略. 要设置多个 OAuth2 策略, 需要添加多个路线, 每个路线都使用不同的策略 authenticate ,然后引导用户选择正确的策略.

多个策略也可以作为实例通过,如果您只打算用于路由处理器或请求.

// use an `authenticate` call can test incoming requests against multiple strategies without registering them for use elsewhere
fastify.get(
  '/',
  {
    preValidation: fastifyPassport.authenticate([new BearerTokenStrategy(), new BasicAuthStrategy()], {
      authInfo: false,
    }),
  },
  async (request, reply, err, user, info, status) => {
    if (err !== null) {
      console.warn(err)
    } else if (user) {
      console.log(`Hello ${user.name}!`)
    }
  }
)

授权( 策略: 字符串 QQ 策略 QQ (字符串 QQ 策略 ) [], 选项: 认证选项 = QQ, 回调

返回将授权使用给定的第三方账户的钩子 strategy,可选 options。旨在用作一种 preValidation 钩上任何路线. .authorize 有与 .authenticate,但有一个关键区别: 它不会修改用户细节中记录的. 相反,如果授权成功,该战略的核查回调结果将分配给 request.account。现有的登录会话和 request.user 将不受影响.

在将第三方账户与目前认证的用户的本地账户连接时,这一功能特别有用.

实例:

fastifyPassport.authorize('twitter-authz', { failureRedirect: '/account' })

.authorize 允许通过通过一系列战略名称来使用多种战略,并允许通过通过将实例作为战略来使用已经即时的战略实例,或一系列实例.

使用( 名称? : 字符串, 策略: 策略)

使用给定的 strategy 可选 name,压倒策略的默认名称.

实例:

fastifyPassport.use(new TwitterStrategy(...));

fastifyPassport.use('api', new http.Strategy(...));

未使用( 名称: 字符串)

取消对 strategy 给定 name。 。 。 .

在典型的应用程序中,必要的认证策略是静态的,配置一次,总是可用的. 因此,往往没有必要援引这一职能.

然而,在某些情况下,应用程序可能需要动态配置和去配置认证策略. 这个 use()编号 :unuse() 组合满足了这些设想.

示例

fastifyPassport.unuse('legacy-api')

注册用户序列器( 序列器 ): (用户, 请求) QQ 承诺)

注册一个同步用户序列器功能,用于从您的应用程序中取出一个高级用户对象并将其序列化存储到会话中. @fastify/passport 无法在会话中存储丰富的对象类, 只保存 JSON 对象, 因此, 如果您想要从数据库中获取用户对象, 您必须注册序列器/ 删除器对, 并且只存储会话中的用户 ID .

// register a serializer that stores the user object's id in the session ...
fastifyPassport.registerUserSerializer(async (user, request) => user.id)

用户定义器( 定义器 :( 序列化用户, 请求) QQ 承诺)

注册一个 async 用户 deserializer 函数,用于从会话中取出一个低级序列化用户对象(通常只是用户ID),并将其从存储到请求上下文中去除. @fastify/passport 无法在会话中存储丰富的对象类, 只保存 JSON 对象, 因此, 如果您想要从数据库中获取用户对象, 您必须注册序列器/ 删除器对, 并且只存储会话中的用户 ID .

fastifyPassport.registerUserDeserializer(async (id, request) => {
  return await User.findById(id);
});

断层器可以抛出字符串 "pass" 如果它们不适用于本届会议,则应审判下一个破坏者。 如果您正在使用此选项, 则此选项将有所帮助 @fastify/passport 以存储两种不同的用户对象。 一个例子是:

// register a deserializer for database users
fastifyPassport.registerUserDeserializer(async (id, request) => {
  if (id.startsWith("db-")) {
    return await User.findById(id);
  } else {
    throw "pass"
  }
});

// register a deserializer for redis users
fastifyPassport.registerUserDeserializer(async (id, request) => {
  if (id.startsWith("redis-")) {
    return await redis.get(id);
  } else {
    throw "pass"
  }
});

会话可以指定自此被从存储用于应用程序的数据存储所删除的序列化用户. 在这种情况下,去序列化往往失败,因为无法为给定的ID找到用户行. 根据应用程序的不同,这可能是一个出错条件,或者如果用户在登录时被从数据库中删除,预计会是这样. @fastify/passport本案中的行为可以形容. 如果解析器返回未定义, 错误会被丢出; 如果解析器返回, 会话会被记录出去 null 或者说 false. 这符合原作的行为 passport 模块.

因此,一个破坏者可以返回一些东西:

  • 如果一个去序列器返回一个对象,则该对象被假定为成功去序列化用户
  • 如果一个破坏者返回 undefined, (中文(简体) ), @fastify/passport 将它解释为错误地缺失的用户,并扔出一个错误,因为用户无法被解析.
  • 如果一个破坏者返回 null 或者说 false, (中文(简体) ), @fastify/passport 将它解释为缺失但预期的用户,并将会话重排以登录用户退出
  • 如果断层器抛出字符串 "pass", (中文(简体) ), @fastify/passport 将尝试下一个去序列化器,如果它存在的话,或者由于用户无法去序列化而丢出一个错误.

请求# is 认证( )

测试请求是否包含登录会话, 即是否 request.user 居住人口 secureSession() 或由先前 authenticate() 电话 这就是应该保护的路线 保护路线。 。 。 .

server.get('/', {
  preValidation: async (request, reply) => {
    if (!request.isAuthenticated()) return reply.redirect('/auth/login')
  }
}, async (request) => request.user)

请求# 是未经认证的 ()

测试请求是否未经认证.

使用类型脚本

@fastify/passport 以 TypeScript 写成,所以它包括了它所有API的类型定义. 也可以强烈地输入 FastifyRequest.user 属性使用 TypeScript 声明合并。 你必须重新宣布 PassportUser 接口 fastify 模块,用于在认证时添加策略指定的属性 :

declare module 'fastify' {
  interface PassportUser {
    id: string
  }
}

或者,如果您已经拥有从所有策略中返回的对象的类型,您可以制作 PassportUser 扩展它:

import { User } from './my/types'

declare module 'fastify' {
  interface PassportUser extends User {}
}

使用多个实例

@fastify/passport 支持在不同插件封装上下文中多次注册。 这对执行两个独立的认证堆栈很有用. 例如,你可能有一套战略来认证你的应用程序的用户,还有一套其他战略来认证进入某一行政区域的应用程序的工作人员。 用户可能存储于 request.user,和管理员 request.admin,而一个伐木 不应该影响另一个。 必须登记每个实例: @fastify/passport 在不同的快捷插件上下文中使装饰器 @fastify/passport 喜欢 request.logIn 财务报告和审定财务报表 request.logOut 别撞了.

要登记@ fastify/ passport 不止一次, 您必须即刻获取更多不同的副本 keys 财务报告和审定财务报表 userProperty因此,它们不会在装饰您固定实例或存储会话时碰撞.

import { Authenticator } from '@fastify/passport'

const server = fastify()

// users: their own Authenticator, hooks and routes, inside their own plugin context
server.register(async (instance) => {
  const userPassport = new Authenticator({ key: 'users', userProperty: 'user' })
  userPassport.use('some-strategy', new CoolOAuthStrategy('some-strategy'))
  instance.register(userPassport.initialize())
  instance.register(userPassport.secureSession())

  instance.get('/login', { preValidation: userPassport.authenticate('some-strategy') }, () => {})
  instance.get(
    '/login/callback',
    { preValidation: userPassport.authenticate('some-strategy', { successRedirect: '/' }) },
    () => {}
  )
  instance.get(
    '/',
    {
      preValidation: async (request, reply) => {
        if (!request.isAuthenticated()) return reply.redirect('/login')
      }
    },
    async (request) => `hello ${JSON.stringify(request.user)}!`
  )
})

// administrators: the same, in a separate context so the decorators don't collide
server.register(async (instance) => {
  const adminPassport = new Authenticator({ key: 'admin', userProperty: 'admin' })
  adminPassport.use('admin-google', new GoogleOAuth2Strategy('admin-google'))
  instance.register(adminPassport.initialize())
  instance.register(adminPassport.secureSession())

  instance.get('/admin/login', { preValidation: adminPassport.authenticate('admin-google') }, () => {})
  instance.get(
    '/admin/login/callback',
    { preValidation: adminPassport.authenticate('admin-google', { successRedirect: '/admin' }) },
    () => {}
  )
  instance.get(
    '/admin',
    {
      preValidation: async (request, reply) => {
        if (!request.isAuthenticated()) return reply.redirect('/admin/login')
      }
    },
    async (request) => `hello administrator ${JSON.stringify(request.admin)}!`
  )
})

说明: 每个 Authenticator 实例初始化插件和会话插件必须单独注册.

必须指出的是,使用多种方法 @fastify/passport 如果想要使用多个策略登录同一类型的用户,则不需要实例. @fastify/passport 将数组传递到任意 .authenticate 电话.

与护照的区别

@fastify/passport 是一个经过修改的护照版本,试图尽可能兼容,但是一个经过修改的版本,有一些不相容之处. 坚持护照策略的护照策略API应该很好,但为了更好地与Fastify结合并坚持Fastify的性能主题而制作的其他API有一些不同.

差异:

  • serializeUser 重新命名为 registerUserSerializer 并总是使用签名的同步函数 (user: User, request: FastifyRequest) => Promise<SerializedUser>
  • deserializeUser 重新命名为 registerUserDeserializer 并总是使用签名的同步函数 (serialized: SerializedUser, request: FastifyRequest) => Promise<User>
  • transformAuthInfo 重新命名为 registerAuthInfoTransformer 并总是使用签名的同步函数 (info: any, request: FastifyRequest) => Promise<any>
  • .authenticate 财务报告和审定财务报表 .authorize 除战略名称外,接受战略实例。 这使得可以使用一次性战略实例(例如测试给定的用户资格),而不将它们添加到全球已登记战略清单中.

许可证

麻省理工学院

版本与发布记录

@fastify/passport 共发布 18 个版本,首次发布于 2022/04/27;过去 12 个月发布了 5 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
4.0.4latest2026/10/101 个月前
4.0.32026/09/231 个月前
4.0.22026/08/133 个月前
4.0.12026/07/283 个月前
4.0.02026/07/263 个月前
3.0.22025/01/111.8 年前

其他发布通道:one → 1.1.0,next → 3.0.0。

关于 @fastify/passport 的常见问题

@fastify/passport 是什么?

简单,无侵扰性的快速认证.

如何安装 @fastify/passport?

在项目目录运行 npm install @fastify/passport,或使用 pnpm add / yarn add / bun add。

@fastify/passport 支持 TypeScript 吗?

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

@fastify/passport 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@fastify/passport 可以商用吗?

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

@fastify/passport 的下载量有多少?

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

@fastify/passport 还在维护吗?

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