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