我正在使用express框架开发Nuxt服务器端呈现的应用程序。为了进行身份验证,我使用的是openid-client软件包。现在,我想将检索到的令牌存储在快速会话中,但在回调承诺中始终未定义请求模型(req)。为此,我想使用req.session.token = tokenSet.access_token。我是JavaScript的新手,所以我认为我缺少明显的东西。
我尝试了各种关于如何将变量传递到JavaScript Promise的选项,但是所有这些都要求您自己定义Promise,这不是我的情况。我还尝试了等待promise,并在回调promise之外使用它,但是也没有成功。
router.get('/api/oidc-callback', (req, res, params) => {
Issuer.discover('http://localhost:5000') // => Promise
.then(function(identityIssuer) {
const client = new identityIssuer.Client({
...
})
// HERE IT IS DEFINED
console.log(req)
client
.callback('http://localhost:3000/api/oidc-callback', req.query, {
code_verifier
})
// => Promise
.then(function(tokenSet) {
// HERE IT IS UNDEFINED
console.log(req)
req.session.token = tokenSet.access_token
}, req)
.catch(error => {
console.log(error)
})
//Also tried using outside
res.redirect('/oidc-callback')
})
})
在此先感谢您的帮助!
答案 0 :(得分:1)
我相信req之所以未定义的原因是,在执行中间件(res,req,next)=> {...}之后,promise被解决了。尝试返回顶级承诺,即(res,req,next)=> {return Issuer.discover(...)},并在client.callback(...)之前添加return语句。
router.get('/api/oidc-callback', (req, res, params) => {
return Issuer.discover('http://localhost:5000') // <-- added return here
.then(function(identityIssuer) {
const client = new identityIssuer.Client({
...
})
// HERE IT IS DEFINED
console.log(req)
return client // <-- added return here
.callback('http://localhost:3000/api/oidc-callback', req.query, {
code_verifier
})
// => Promise
.then(function(tokenSet) {
// HERE IT IS UNDEFINED
console.log(req)
req.session.token = tokenSet.access_token
res.redirect('/oidc-callback')
}) // removed , req here, it is not needed
.catch(error => {
console.log(error)
})
})
})
通过添加return语句,它告诉express您正在运行一个异步函数,因此,express它要等到您的中间件解决后再继续进行下一个中间件。
答案 1 :(得分:0)
您有两个嵌套的异步操作(此处简化显示),然后尝试在第一个.then()
处理程序中做最后的事情:
Issuer.discover().then(function() {
client.callback().then(function() {
// ...
});
res.redirect('/oidc-callback');
});
这将导致res.redirect()
在完成client.callback()
之前被调用,因为您的代码中没有任何内容使其等待client.callback()
的完成。这将发送响应并触发重定向,然后再修改会话(这不是您要执行的操作)。您可以通过以下两种方法之一来解决此问题:
1)像这样将res.redirect()
放在内部.then()
内:
Issuer.discover().then(function() {
client.callback().then(function() {
// ...
res.redirect('/oidc-callback');
});
});
2)在return
之前添加client.callback()
,以便将内部承诺链接到外部承诺。然后,直到完成内部的一个,外部的一个才会完成,您可以添加另一个.then()
处理程序以将res.redirect()
放入:
Issuer.discover().then(function() {
return client.callback().then(function() {
// ...
});
})。then(function(){ //当两个异步操作都完成时被调用 res.redirect('/ oidc-callback'); });
我建议选择#2,因为它可以使错误处理更加简单,因为您可以在顶层的一个位置进行所有错误处理。综合所有这些,您最终会得到以下结果:
router.get('/api/oidc-callback', (req, res, params) => {
Issuer.discover('http://localhost:5000').then(function(identityIssuer) {
const client = new identityIssuer.Client({
...
})
return client.callback('http://localhost:3000/api/oidc-callback', req.query, {
code_verifier
}).then(function(tokenSet) {
console.log(req);
req.session.token = tokenSet.access_token
}, req);
}).then(() => {
res.redirect('/oidc-callback');
}).catch(err => {
console.log(err);
res.sendStatus(500);
});
});
注意,我还在最后添加了适当的错误处理。这样可以确保在您完成两个异步操作之前都不会发送响应,并且如果其中任何一个失败,它都会发送正确的错误响应。