我正在构建一个具有不同前端的解耦 keystonejs (keystonejs 6) 应用程序,它将使用其 graphql api 从主 keystonejs 实例中提取和推送数据。
我已经设置了访问控制来满足我的需求,并且通过 AdminUI 一切正常,但是当我尝试从外部前端之一执行登录时,在 keystone 实例上没有创建任何会话。
我正在启动突变
AuthenticateUserWithPassword
,它返回会话令牌(因此登录本身正在工作)并在浏览器中设置 keystonejs-session
cookie。我还尝试在 fetch()
请求标头中手动设置此 cookie 并执行查询,但我的外部前端不允许这样做。
mutation AuthenticateUserWithPassword($email: String!, $password: String!) {
authenticateUserWithPassword(email: $email, password: $password) {
... on UserAuthenticationWithPasswordSuccess {
sessionToken
item {
email
}
}
... on UserAuthenticationWithPasswordFailure {
message
}
}
}
有趣的是,如果我从前端登录并返回 AdminUI,我已登录并可以执行经过身份验证的查询,并且如果我在 AdminUI 上执行任何操作时检查 context.session,我就有一个会话对象,但是当我从外部前端执行任何操作时,会话为空(但我使用相同的 cookie)
从 AdminUI 发出请求时的会话日志,例如
session: {
listKey: 'User',
itemId: '1234567890a123445656',
data: {
id: '1234567890a123445656',
name: 'myUserName',
createdAt: 'whateverdate'
}
}
从外部前端发出请求时的会话日志,例如
session: undefined
除了
keystonejs-session
cookie 之外,我还必须在来自外部前端的查询的标头中发送任何其他内容,以使 keystonejs 识别我经过身份验证的用户并使用该会话吗?
好吧,一如既往,在解决这个问题几天后,我只需将其写在 StackOverflow 中,然后一个新想法就出现在我的脑海中。
在尝试了 Keystonejs 文档中的所有内容之后,我刚刚开始调试他们的源代码,似乎有一个带有标准标头的未记录的身份验证功能:
authorization: Bearer + <token>
幸运的是,我刚刚为不同的机制开发了自定义承载身份验证,但我不知道 keystone 正在检查该标头中的某些内容。
不仅要查看它,而且如果存在持有者,会话 cookie 也会被忽略:
const token = bearer || cookies[cookieName];
(来自
node_modules/@keystone-6/core/session/dist/keystone-6-core-session.cjs.dev.js
)
async get({
context
}) {
var _context$req$headers$;
if (!(context !== null && context !== void 0 && context.req)) return;
const cookies = cookie__namespace.parse(context.req.headers.cookie || '');
const bearer = (_context$req$headers$ = context.req.headers.authorization) === null || _context$req$headers$ === void 0 ? void 0 : _context$req$headers$.replace('Bearer ', '');
const token = bearer || cookies[cookieName];
if (!token) return;
try {
return await Iron__default["default"].unseal(token, secret, ironOptions);
} catch (err) { }
},
所以,这个故事的寓意是:如果存在会话 cookie,切勿使用 Bearer 令牌,或者至少在使用 Keystonejs 时不要这样做