资讯详情

资讯详情

Keystone 6 密码认证完整指南:使用 createAuth() 构建登录体系

后端【免费下载链接】keystoneThe superpowered headless CMS for Node.js — built with GraphQL and React项目地址https://gitcode.com/gh_mirrors/key/keystone点击查看免费下载导读本文围绕keystone-6/auth包中的createAuth()函数系统讲解如何在 Keystone 6 中为应用接入基于password字段的认证能力从withAuth包装config()的接入方式到必选/可选配置项、自动注入的 GraphQL API、Admin UI 登录页再到sessionData的会话数据注入原理。读完本文你将能够独立为一个 Keystone 系统配置「账号密码 会话 访问控制」的完整认证链路。认证机制总览createAuth 与 withAuthKeystone 允许通过keystone-6/auth包中的createAuth()函数将系统扩展为支持针对某个列表List上的password字段进行认证。其核心用法如下import { config, list } from keystone-6/core import { text, password, checkbox } from keystone-6/core/fields import { createAuth } from keystone-6/auth const { withAuth } createAuth({ // Required options listKey: User, identityField: email, secretField: password, // Additional options sessionData: id email, }) export default withAuth( config({ lists: { User: list({ fields: { email: text({ isIndexed: unique }), password: password(), isAdmin: checkbox(), }, }), }, session: { /* ... */ }, }) )createAuth返回一个名为withAuth的函数用它包裹你的config()即可。这个包装函数会修改配置对象向系统中注入额外字段、额外 GraphQL query/mutation 以及自定义 Admin UI 功能。并且createAuth必须与 session 配置 配合使用。从源码看withAuth的注入动作在 packages/auth/src/index.ts 中完成具体包括校验配置合法性throwIfInvalidConfig通过getAdditionalFiles向 Admin UI 构建产物写入 signin 页面文件通过extendGraphqlSchema组合注入认证相关的 GraphQL schemaschema.ts用authSessionStrategy包装你传入的 session strategy实现session.data的自动填充。需要说明的是keystone-6/auth只是基于 Keystone 底层 API 的一种「有主见」的默认实现。如果你想自定义认证流程例如集成 OAuth完全可以参照它 fork 一份自己的实现会话管理同样如此。必选配置项认证系统的核心能力是提供一个 GraphQL mutation 用于认证用户并开启会话以及在 Admin UI 中提供登录页面。三个必选配置项如下配置项说明约束listKey用于认证的列表名称列表必须真实存在否则withAuth会抛出withAuth cannot find the list ...错误identityField作为身份标识的字段名该字段必须设置{ isIndexed: unique }secretField作为秘密口令的字段名必须是password()字段类型最小配置示例import { createAuth } from keystone-6/auth const { withAuth } createAuth({ listKey: User, identityField: email, secretField: password, })字段约束的源码依据在 packages/auth/src/schema.ts 中getSchemaExtension会检查identityField在列表的WhereUniqueInput中是否可被 String/ID 唯一检索若否则抛出错误提示你应该给该字段添加isIndexed: unique同时 getBaseAuthSchema.ts 通过getPasswordFieldKDF校验secretField必须是合法的 password 字段否则抛出${listKey}.${secretField} is not a valid password field.。GraphQL API开启认证后以下元素会被加入 GraphQL APItype Mutation { authenticateUserWithPassword( email: String! password: String! ): UserAuthenticationWithPasswordResult! } type Query { authenticatedItem: AuthenticatedItem } union AuthenticatedItem User union UserAuthenticationWithPasswordResult | UserAuthenticationWithPasswordSuccess | UserAuthenticationWithPasswordFailure type UserAuthenticationWithPasswordSuccess { sessionToken: String! item: User! } type UserAuthenticationWithPasswordFailure { message: String! }命名规则上述 GraphQL 名称并非硬编码。从 index.ts 中的 getAuthGqlNames 可以看出mutation 名由authenticate${GraphQL单数名}WithPassword拼接而来对应listKey: User时即authenticateUserWithPasswordunion 及各类型同理。authenticateUserWithPassword该 mutation 会校验提交的凭据若合法则开启一个新的 session。它的参数名正是identityField与secretField的值。mutation { authenticateUserWithPassword(email: usernameexample.com, password: password) { ... on UserAuthenticationWithPasswordSuccess { item { id email } } ... on UserAuthenticationWithPasswordFailure { message } } }成功时会话处理器会开启新会话并把编码后的会话 cookie 数据作为sessionToken返回已认证的用户对象作为item返回。失败时返回{ code: FAILURE, message: Authentication failed. }。这个常量定义在 getBaseAuthSchema.tsresolve实现中所有失败路径都返回它调用方只能通过message感知失败而无法区分「用户不存在」与「密码错误」。值得关注的实现细节见 getBaseAuthSchema.ts认证查询通过context.sudo().db[listKey].findOne(...)执行即绕过访问控制直接按identityField查找用户当用户不存在或 secret 字段不是字符串时会执行一次kdf.hash(simulated-password-to-counter-timing-attack)用模拟哈希来抵消基于响应时间的用户枚举攻击密码校验使用 password 字段类型底层的 KDFcompare确保存储的是哈希而非明文校验通过后调用context.sessionStrategy.start({ data: { itemId: item.id }, context })启动会话。authenticatedItem该 query 基于session数据返回当前登录用户没有会话时返回nullgetBaseAuthSchema.ts。此外源码中还额外注入了endSessionmutation用于结束当前会话内部调用context.sessionStrategy.end({ context })这也是从 GraphQL 层主动登出的标准途径。Admin UI启用认证后Admin UI 会新增/signin登录页。未登录用户访问 Admin UI 会被重定向回/signin该页面内部正是调用authenticateUserWithPasswordmutation 完成登录的。实现细节在 index.ts 中authGetAdditionalFiles会把渲染好的pages/signin.js与config.ts写入 Admin UI 构建产物signin 页面模板见 templates/signin.ts页面组件实现位于 pages/SigninPage.tsx。同时index.tsauthPublicPages会把${basePath}/signin追加进ui.publicPages使其成为公开页面通过pageMiddleware包装authMiddleware在wasAccessAllowed为假时返回{ kind: redirect, to: basePath /signin }其余情况再交给用户自定义的pageMiddleware默认的isAccessAllowed逻辑是session ! undefinedindex.ts你可以像 examples/auth/keystone.ts 那样覆盖它例如只允许管理员进入 Admin UI。可选配置项以下选项为认证系统添加额外功能默认处于禁用/默认状态。sessionDatasessionData用于在认证时设置自定义的session.data值。认证 mutation 会在context.session对象上设置{ listKey, itemId }。但在做访问控制或使用 hooks 时你往往需要比itemId更多的用户信息。配置sessionData后系统会根据itemId查询对应字段并填充到session.data。其值是一段 GraphQL 查询字符串指明要把哪些字段填充到session.data上import { createAuth } from keystone-6/auth const { withAuth } createAuth({ listKey: User, identityField: email, secretField: password, sessionData: id name isAdmin, })源码行为sessionData的默认值是id见 index.ts 的参数默认值。填充动作发生在authSessionStrategy.get中index.ts每次请求时先取底层 session再用sudo context执行query[listKey].findOne({ where: { id: session.itemId }, query: sessionData })拉取数据——注意 types.ts 中明确标注了「WARNING: uses sudo to retrieve this data」即该查询会绕过访问控制因此不要往sessionData里塞你不想让用户看到的字段。查询失败或数据不存在时session会被置为undefined等价于未登录。同时schema.ts 会在启动阶段把sessionData拼成query($id: ID!) { item(where: { id: $id }) { ${sessionData} } }交给 GraphQL 解析与校验语法错误会提示「the sessionData option in your createAuth usage is likely incorrect」校验错误则会直接列出具体报错帮助你在开发期尽早发现问题。典型用法把sessionData配成isAdmin后就可以在列表的access中这样判断const isAdmin ({ session }: { session?: Session }) Boolean(session?.data.isAdmin)关于sessionData与 operation/filter/item 三级访问控制如何组合使用参见 访问控制指南。与 Session 配置协同完整可运行示例createAuth必须与config.session一起使用否则withAuth会抛出TypeError: Missing .session configurationindex.ts。官方示例项目 examples/auth 给出了开箱即用的完整配置import { PrismaBetterSqlite3 } from prisma/adapter-better-sqlite3 import { config } from keystone-6/core import { statelessSessions } from keystone-6/core/session import { createAuth } from keystone-6/auth import { type Session, lists } from ./schema import type { TypeInfo } from ./generated/keystone/types // WARNING: 生产环境必须更换此密钥 const sessionSecret -- DEV COOKIE SECRET; CHANGE ME -- // 会话 cookie 有效期单位为秒示例中设为 1 小时 const sessionMaxAge 60 * 60 const { withAuth } createAuth({ listKey: User, // 存放用户的列表 identityField: name, // 身份字段通常为用户名或邮箱 secretField: password, // 秘密字段必须是 password 字段类型 sessionData: isAdmin, // 把 isAdmin 注入会话数据 }) export default withAuthTypeInfoSession( configTypeInfo({ db: { provider: sqlite, prismaClientOptions: () ({ adapter: new PrismaBetterSqlite3({ url: process.env.DATABASE_URL ?? file:./keystone-example.db, }), }), async onConnect(context) { // 开发辅助首次启动自动创建初始管理员账号生产环境请勿使用 ;(async () { const sudoContext context.sudo() if ((await sudoContext.db.User.count()) ! 0) return const password crypto.getRandomValues(new Uint8Array(16)).toHex() await sudoContext.db.User.createOne({ data: { name: admin, password, isAdmin: true } }) console.log(Created initial user: admin / ${password}) })().catch(error console.error(Failed to create initial user:, error)) }, }, lists, ui: { // 仅管理员可进入 Admin UI isAccessAllowed: context { return context.session?.data?.isAdmin ?? false }, }, session: statelessSessions({ maxAge: sessionMaxAge, secret: sessionSecret, }), }) )这里用到了statelessSessions它属于 Session 配置文档 中的两种会话策略之一无状态会话statelessSessions所有会话数据都存放在加密 cookie 中无需服务端存储有状态会话storedSessionscookie 只存放 session ID通过store参数提供的set/get/delete接口在服务端存取数据。两种策略的 cookie 均使用hapi/iron加密常用参数包括secret必填至少 32 个字符、maxAge默认 8 小时、secure默认NODE_ENV production、path、domain、sameSite默认lax等。认证 mutation 的start/end正是通过这些 session strategy 完成会话的开启与结束。测试验证仓库为认证功能提供了自动化测试覆盖可作为行为验证与参考tests/api-tests/auth.test.ts 与 tests/api-tests/auth-header.test.ts覆盖认证 mutation 的完整流程tests/examples-smoke-tests/auth.test.ts对 examples/auth 示例做冒烟测试tests2/access.*.test.ts 系列测试则覆盖了会话与访问控制的组合场景。相关资源Authentication and Access Control 指南认证 会话 访问控制的组合使用教程Session 配置 APIstatelessSessions/storedSessions完整参数说明examples/auth为任务管理启动项目添加密码认证的官方示例keystone-6/auth 源码createAuth/withAuth的完整实现可作为自定义认证方案的起点。赞分享后端【免费下载链接】keystoneThe superpowered headless CMS for Node.js — built with GraphQL and React项目地址https://gitcode.com/gh_mirrors/key/keystone点击查看免费下载相关推荐Keystone 6 认证模块演进全解从 keystone-6/auth 版本变更看密码认证与 Session 架构Keystone 6 认证模块演进全解从 keystone 6/auth 版本变更看密码认证与 Session 架构 本指南以当前仓库中 packages/后端打造个性化终端体验Termux:Styling深度配置指南打造个性化终端体验Termux:Styling深度配置指南 在移动开发和工作流程中Termux已成为Android平台上不可或缺的终端模拟器而Termux移动开发Wasp 认证 UI 完整指南从零构建登录、注册与密码找回页面Wasp 认证 UI 完整指南从零构建登录、注册与密码找回页面 本指南以 Waspwaspc开源仓库的 version 0.15 版本文档为核心系统讲解Web框架后端前端CLI开发工具上一篇CSDN博客下载器终极指南教你如何免费快速保存技术文章下一篇如何快速安装网盘直链下载助手新手完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →