mcpField
N
netlify-identity

netlify-identity

github.com/netlify安全473.1k 次安装6 天前更新
代码仓库

关于 netlify-identity

netlify-identity 是一项指导开发者在 Netlify 应用中实现身份验证与授权的技能,适用于浏览器和 Netlify Functions、Edge Functions。它涵盖客户端登录流程、服务器端用户检查、角色控制及身份事件处理,并强调控制台配置和部署测试要求。

主要功能

  1. 01实现注册、登录、登出与 OAuth
  2. 02处理确认、邀请和恢复链接
  3. 03在函数中验证用户与角色
  4. 04通过身份事件限制注册或分配角色
  5. 05使用重定向规则执行边缘 RBAC

适用场景

  1. 01为 Netlify 应用添加用户注册和登录
  2. 02保护函数端点并检查用户角色
  3. 03在注册时验证用户或分配角色

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/netlify/context-and-tools --skill netlify-identity

安装后在 Claude Code 中输入/netlify-identity确认已加载。

附带文件references/advanced-patterns.mdreferences/authorization-and-sessions.md

详细介绍

Netlify Identity

使用 @netlify/identity(npm)。对于新项目,它取代了旧版 netlify-identity-widget 和 gotrue-js,请勿使用它们。

npm install @netlify/identity

框架示例(Next.js/Astro/Remix/SvelteKit)和完整 API 参考见 npm 上的 @netlify/identity README。

Identity 无法在 netlify dev 下运行。 请在部署后测试所有身份验证流程,Deploy Previews 可用。本地开发无法完成注册/登录/OAuth 流程。

Identity 配置只能在控制面板中进行,没有公共 API。 切勿使用 curl 调用 api.netlify.com 来修改或读取 Identity 设置,切勿从本地 Netlify 配置中读取令牌,也切勿探测未公开的端点。请在 https://app.netlify.com/projects/{site_name}/identity 启用并配置 Identity。

切勿在 Identity 旁边从头构建 OAuth 流程。 不要在代码中注册提供商应用,不要在源代码中加入 client_id/secret,也不要自行交换回调令牌。请使用 oauthLogin() + handleAuthCallback()。在 Identity 旁边使用原始 OAuth 是最常见的返工原因。

客户端身份验证(浏览器)

import { signup, login, logout, getUser, oauthLogin, handleAuthCallback } from '@netlify/identity'

// Register — confirmation email sent by default (unless autoconfirm is on)
const user = await signup('[email protected]', 'securepassword', { full_name: 'Jane Doe' })

// Log in / out
await login('[email protected]', 'securepassword')
await logout()

// Current user or null
const current = await getUser()
if (current) console.log(`Logged in as ${current.email}`)

// External provider — redirects the browser; provider is one of
// 'google' | 'github' | 'gitlab' | 'bitbucket'
oauthLogin('github')

必须在着陆页调用 handleAuthCallback()。 如果不调用,OAuth 重定向、电子邮件确认链接、密码恢复链接和邀请链接都无法完成。请在页面加载时调用:

import { handleAuthCallback } from '@netlify/identity'

const result = await handleAuthCallback() // falsy if no token in URL hash
if (result) console.log(result.type, result.user.email) // confirmation | invite | recovery | email change

对于单一令牌类型,可以使用以下替代方法:recoverPassword()(恢复密码)、acceptInvite()(接受邀请)。使用 refreshSession() 刷新会话。

不要将现有提供商写死。请在启动时调用 getSettings(),并根据其返回结果呈现注册表单和 OAuth 按钮。

服务端身份验证(Netlify Functions 和 Edge Functions)

服务端的 getUser()/login()/admin.* 需要现代 v2 functions(export default)。不支持 v1 的 export { handler } 形式。

getUser() 在两种运行时中均可用。admin.* 只能在 Netlify Functions 中运行,不能在浏览器或 Edge Functions 中运行。

// netlify/functions/me.ts — verify user
import { getUser } from '@netlify/identity'
import type { Context } from '@netlify/functions'

export default async (req: Request, context: Context) => {
  const user = await getUser()
  if (!user) return new Response('Unauthorized', { status: 401 })
  return Response.json({ id: user.id, email: user.email })
}

Edge Function 的形式相同,但需要从 @netlify/edge-functions 导入 Context。

角色检查
// netlify/functions/admin-users.ts
import { getUser, admin } from '@netlify/identity'
import type { Context } from '@netlify/functions'

export default async (req: Request, context: Context) => {
  const user = await getUser()
  if (!user) return new Response('Unauthorized', { status: 401 })
  if (!user.roles.includes('admin')) return new Response('Forbidden', { status: 403 })
  const users = await admin.listUsers()
  return Response.json({ users })
}
CSRF:服务端身份验证端点必需

任何在服务端运行 login()、signup() 或 logout() 的端点,都必须在处理程序开头调用 verifyRequestOrigin(req)。来源不匹配时,该函数会抛出 403 错误。

// netlify/functions/login.ts
import { login, verifyRequestOrigin } from '@netlify/identity'
import type { Context } from '@netlify/functions'

export default async (req: Request, context: Context) => {
  verifyRequestOrigin(req)
  const { email, password } = await req.json()
  await login(email, password)
  return new Response(null, { status: 302, headers: { Location: '/dashboard' } })
}

Identity 事件函数

Identity 事件发生时,平台会调用你的处理程序。导出一个包含各事件对应方法的默认对象。文件:netlify/functions/identity.mts。

类型化处理程序(UserSignupEvent、event.deny())需要 @netlify/functions ≥ 5.2.0。旧版安装必须使用传统文件名约定(identity-signup.ts 等),请参阅 references/authorization-and-sessions.md。

处理程序触发时机
userValidate注册尝试期间,在创建账户之前。在此处拦截不合规的注册。
userSignup注册完成时(如果启用了电子邮件确认,则在确认之后)。分配角色、同步数据、发送欢迎信息。
userLogin用户登录时。用于跟踪、记录最近登录时间或拦截用户。
userModified个人资料更新时。
userDeleted用户删除时(仅通知)。

事件中的 user 字段采用驼峰命名(appMetadata、userMetadata、confirmedAt)。

// netlify/functions/identity.mts — deny a signup
import type { UserValidateEvent } from "@netlify/functions"

export default {
  userValidate(event: UserValidateEvent) {
    if (!event.user.email?.endsWith("@example.com")) return event.deny()
  },
}
// netlify/functions/identity.mts — assign roles at signup
import type { UserSignupEvent } from "@netlify/functions"

export default {
  userSignup(event: UserSignupEvent) {
    return { user: { ...event.user, appMetadata: { ...event.user.appMetadata, roles: ["member"] } } }
  },
}
  • event.deny() — 拒绝操作;最终用户会收到 401,不会产生可观测性错误。第一个调用该方法的处理程序会中止调用链,后续订阅者不会被调用。(传统文件名函数则通过返回非 2xx 的 Response 来表示拒绝。)
  • 返回 { user: {...} } 可在持久化之前修改记录(这是在注册时设置角色的规范方式)。角色包含在 JWT 中,因此角色变更要到用户下次登录或刷新令牌时才生效,而非立即生效,请参阅下文的“角色与 JWT”。
  • 后台模式:export const config: Config = { background: true } — 操作会立即完成,处理程序则异步运行。

角色与 JWT

  • user.roles 从 app_metadata.roles 中读取,并随 JWT 携带(cookie nf_jwt;通过 nf_refresh 刷新)。
  • user_metadata — 用户可编辑的个人资料(full_name、email)。app_metadata — 应用数据,包括 roles,用户不可编辑。

角色变更不会立即生效。 它们会在下次登录或刷新令牌时生效。更改角色不会使当前 JWT 失效。调用 refreshSession() 强制刷新。

通过 Netlify Function 中的 admin.updateUser() 为现有用户设置角色;也可以在注册时通过上文的 userSignup 事件处理程序设置。

有关 SSR/会话水合和授权的详细指南,请参阅 references/advanced-patterns.md 和 references/authorization-and-sessions.md。

CDN 边缘 RBAC(重定向规则)

在边缘执行,无需往返源站。角色不匹配时会返回 404,除非你添加回退规则——始终为受角色限制的规则配对回退规则。

_redirects:

/admin/*  /admin/:splat  200!  Role=admin
/admin/*  /login         401!
# Multiple roles chained with commas:
/private/* /private/:splat 200! Role=editor,admin

netlify.toml:

[[redirects]]
  from = "/admin/*"
  to = "/admin/:splat"
  force = true
  status = 200
  conditions = {Role = ["editor", "admin"]}

基于路径的访问控制请使用重定向规则;自定义授权逻辑请使用基于函数的 user.roles 检查。

配置(仅限控制面板)

基础地址:https://app.netlify.com/projects/{site_name}/identity。启用 Enable Identity。Identity 需要 HTTPS — 在自定义域名上集成前,请先设置 SSL。

  • 注册(?tab=registration#registration-preferences):Open(默认,任何人都可以注册)或 Invite only(所有用户,包括使用外部提供商登录的用户,都必须先收到邀请)。
  • 确认 / 自动确认(?tab=emails#confirmation-template):勾选复选框以跳过电子邮件验证。
  • 外部提供商(?tab=registration#external-providers):Google/GitHub/GitLab/Bitbucket。若要使用品牌化 OAuth(显示你的应用名称,而不是“Netlify Identity”),请在提供商处注册你的应用,获取客户端 ID 和密钥,然后在 Netlify 设置界面中输入——不要写入代码。
  • 邀请(?tab=users):输入地址以发送邀请;链接中包含 invite_token。
  • 密码恢复:用户页面 → Send reset password email;链接中包含 recovery_token。
电子邮件(Pro 计划或更高级别)

默认发件人为 [email protected]。自定义 SMTP 发件人和自定义模板都需要 Pro 计划或更高级别。

模板变量(Go 语法):{{ .Email }}、{{ .NewEmail }}(仅限电子邮件地址变更)、{{ .SiteURL }}、{{ .ConfirmationURL }}、{{ .Token }}。

各操作对应的自定义链接哈希片段:

{{ .SiteURL }}/path/#invite_token={{ .Token }}
{{ .SiteURL }}/path/#confirmation_token={{ .Token }}
{{ .SiteURL }}/path/#recovery_token={{ .Token }}
{{ .SiteURL }}/path/#email_change_token={{ .Token }}

自定义模板限制:仅限内联 CSS;图片链接必须使用绝对路径;不得包含 <html>/<head>/<body> 标签;确保构建过程不会更改 Go 模板变量。

审计日志(Pro 计划或更高级别)

?tab=audit-log。使用限定范围的词条进行搜索:author:[string] 或 action:[string]。操作名称:login、logout、user_signedup、user_deleted、user_modified、token_revoked、token_refreshed、user_recovery_requested、user_invited。

外部 JWT 提供商(Enterprise)

仅适用于 Enterprise 计划。你可以使用 Netlify Identity 或外部 JWT 提供商——不能同时使用两者;启用 Netlify Identity 后,无法对第三方 JWT 进行身份验证。

  • 角色路径:Netlify Identity 使用 app_metadata.roles;外部提供商使用 app_metadata.authorization.roles。自定义路径 → 联系支持团队。
  • JWT 标头必须为 {"alg": "HS256", "typ": "JWT"}(必须使用 HS256)。必须提供负载 exp,且其值必须是未来的 Unix Epoch 时间。
  • 在 Project configuration > General > Visitor access > JWT secret 中设置 JWT 密钥。项目级设置会覆盖团队级默认设置。

失败时——停止,不要猜测

如果回调返回 404、无法访问 /.netlify/identity/*,或 OAuth 流程始终没有返回:说明错误、仪表板 URL(https://app.netlify.com/projects/{site_name}/identity)以及要检查的设置(注册偏好、外部提供方配置、确认/自动确认),然后停止。不要编造恢复命令。请记住:Identity 无法在 netlify dev 下运行——请确认你是在部署环境中测试。

针对站点访问控制的请求(“将此站点限制为仅公司员工访问”)应先交由 netlify-access-control skill 处理——Identity 仅负责应用层用户管理。

Netlify 内部规范(identity)

这些是组织规范,不是文档事实——由 ctx-gen 合并到渲染后的 skill 中,不会自动生成。由 skills 维护者负责。

  1. 深入指南位于此 skill 中:references/advanced-patterns.md (SSR/会话水合)和 references/authorization-and-sessions.md。
  2. Identity 无法在 netlify dev 下运行——请在部署环境中测试身份验证流程 (Deploy Previews 可用)。
  3. Identity 配置没有公共 API——只能在仪表板中操作。绝不要使用 curl api.netlify.com 来切换或查看 Identity 设置,绝不要从 ~/Library/Preferences/netlify/config.json 读取身份验证令牌,也不要探测未公开的端点。
  4. 失败时(回调返回 404、无法访问 /.netlify/identity/*、OAuth 流程没有返回),说明错误、仪表板 URL 和要检查的设置,然后停止。不要编造恢复命令。
  5. 如果使用 Identity,绝不要从头构建第三方 OAuth 流程——不要注册提供方应用,不要在代码中使用 client_id/secret,也不要自定义回调令牌交换。使用 oauthLogin() + handleAuthCallback();在 Identity 旁实现原始 OAuth 流程是最常见的返工原因。
  6. 服务端的 getUser()/login()/admin.* 需要使用现代 v2 函数 (export default)——不支持 v1 的 export { handler }。类型化的 Identity 事件处理程序(UserSignupEvent、event.deny())需要 @netlify/functions ≥ 5.2.0;较旧的安装需使用旧版文件名。
  7. 不要硬编码有哪些身份验证提供方——请在启动时调用 getSettings(),并根据返回结果渲染注册表单和 OAuth 按钮。
  8. 针对站点访问控制的请求(“将此站点限制为仅公司员工访问”)应先交由 netlify-access-control skill 处理——Identity 仅负责应用层用户管理。
  9. 任何分配或更改角色的回答——无论是在注册时、通过 admin.*,还是在仪表板中——都必须说明:更改会在用户下次登录或刷新令牌后生效,而非立即生效。请将这句话放在设置角色的代码旁边,而不是只放在单独的 JWT 部分:回答注册问题的 Agent 会查看注册示例后就停止,而已有答案确实遗漏了这段延迟说明。

评论

支持 Markdown