Как я могу использовать объект запроса во вложенном обещании? - PullRequest
0 голосов
/ 16 июня 2019

Я работаю над приложением Nuxt на стороне сервера с экспресс-фреймворком.Для аутентификации я использую пакет openid-client.Теперь я хочу сохранить полученный извлеченный токен в экспресс-сеансе, но модель запроса (req) всегда не определена в обещании обратного вызова.Для этого я хочу использовать req.session.token = tokenSet.access_token.Я новичок в JavaScript, поэтому мне кажется, что я упускаю что-то очевидное.

Я пробовал различные варианты передачи переменных в обещание JavaScript, но все они требовали, чтобы вы сами определяли обещание, которое не является моимдело.Я также пытался дождаться обещания и использовать его вне обещания обратного вызова, но также не увенчался успехом.

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')
    })
})

Заранее спасибо за вашу помощь!

Ответы [ 2 ]

1 голос
/ 16 июня 2019

Я считаю, что причина, по которой req не определена, потому что обещание было выполнено после выполнения промежуточного программного обеспечения (res, req, next) => {...}. Попробуйте вернуть обещание верхнего уровня, т.е. (res, req, next) => {return Issuer.discover (...)}, также добавьте оператор return перед client.callback (...).

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, что вы запускаете асинхронную функцию, и выражает, что он будет ждать, пока ваше промежуточное ПО будет разрешено, прежде чем перейти к следующему промежуточному ПО.

0 голосов
/ 16 июня 2019

У вас есть две вложенные асинхронные операции (здесь показано упрощенно), а затем вы пытаетесь выполнить что-то последнее в первом обработчике .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);
    });
});

Обратите внимание, в конце я также добавил правильную обработку ошибок.Это гарантирует, что ответ не будет отправлен до тех пор, пока не будут выполнены обе ваши асинхронные операции, и в случае сбоя одного из них он отправит правильный ответ об ошибке.

...