Вызов службы NGINX для токена доступа к API в конфигурации шлюза / прокси API

У меня есть шлюз nginx, настроенный как обратный прокси-сервер API Gateway для Google Cloud API, который использует мод nginx Javascript (njs)

Мой default.conf выглядит так:

      js_include conf.d/oauth2.js; # Location of JavaScript code
js_set $gToken getGoogleAccessToken;

server {
    listen       80;

        server_name test.apigateway.com;


        location / {
                proxy_set_header Authorization $gToken;
                proxy_pass https://GoogleApithatRequiresAuthentcationURL;
        }


        location /_oauth_google {
                internal;
                proxy_method      GET;
                proxy_set_header Authorization "";
                proxy_pass        http://localhost:19006/get-token;
        }

Мой oath2.js njs (Javascript) выглядит так:

      

function getGoogleAccessToken(r) {
    r.subrequest('/_oauth_google',
        function(reply) {
            if (reply.status == 200) {
                var response = JSON.parse(reply.responseBody);
                if (response.access_token !== undefined) {
                    r.log(response.access_token)
                    return("Bearer " + response.access_token); // Token is valid, return token
                } else {
                    r.return(401); // Token is invalid, return forbidden code
                }
            } else {
                r.return(401); // Unexpected response, return 'auth required'
            }
        }
   )
}

По адресу http: // localhost:19006 / get-token существует служба сопутствующих токенов, которая создает RS-SHA256 JWT (см. Код ниже), а также управляет токенами доступа Google и возвращает их. Этот сервис работает без проблем.

Код почти работает с файлом журнала NGINX в режиме отладки. Значение для $gToken кажется нулевым или пустым, когда прокси вызывает API Google, несмотря на то, что r.log(response.access_token) записывается в журнал отладки.

В журналах вроде бы написано, что звонок на js_set $gToken getGoogleAccessToken; не блокирует, так что proxy_pass https://GoogleApithatRequiresAuthentcationURL выполняется до $gTokenустановлен. Документация для js_set указывает, что переменная должна быть установлена ​​при первом доступе, так что это будет, когда proxy_set_header Authorization $gTokenназывается; Заголовок авторизации отсутствует в журнале отладки для вызова https: // GoogleApithatRequiresAuthentcationURL.

Любые идеи, как сделать эту работу, будут оценены. Нет действительно хороших рецептов nginx для проксирования API, для которых требуется токен.

Вот рабочий код для службы токенов Google, которая управляет токеном Google прокси-сервера NGINX, но его можно адаптировать для других служб токенов:

      const jsrsasign = require('jsrsasign');
const fs = require('fs');
const axios = require('axios');
const express = require('express');
const port = process.env.PORT || 19006;
const app = express();
const NodeCache = require( "node-cache" );
const myCache = new NodeCache();
var querystring = require('querystring');

app.get('/get-g-token', async (req, res) => {
    var gToken = myCache.get("gToken");
    if (gToken === undefined) {
      const sJWT = getJWT();
      try{
          const resp = await getGoogleToken(sJWT);
          console.log(resp.data);
          myCache.set( "gToken", resp.data, 3550 )
          res.status = resp.status;
          res.send(resp.data);
      }
      catch(err){
          console.log(err);
          res.status = 500;
          res.send(err.message);
      }
    }
    res.status = 200;
    res.send(gToken);  
});

function getJWT(){
  var kid = "yourgooogleprivatekeyid";
    var header = {
        "alg": "RS256",
        "kid":  kid,
        "typ": "JWT",
    };
    var data = {
        exp: Math.round(new Date().getTime() / 1000) + 3600,
        iat: Math.round(new Date().getTime() / 1000),
        iss: "service-account@project.iam.gserviceaccount.com",
        aud: "https://oauth2.googleapis.com/token",
        scope: "https://www.googleapis.com/auth/cloud-platform",
    };
    var secret = fs.readFileSync('location-of-service-account.pem');
    console.log(secret.toString());
    console.log(header);
    console.log(data);
    var sPayload = JSON.stringify(data);
    var sJWT = jsrsasign.KJUR.jws.JWS.sign("RS256", header, sPayload, secret.toString());
    console.log(sJWT);
    return sJWT;
}

async function getGoogleToken(sJWT)   {
    try {
      let config = {
            headers: {
              "Content-Type": "application/x-www-form-urlencoded",
            }
      } 
      const data = {
        grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
        assertion: sJWT
      }
      return axios.post('https://oauth2.googleapis.com/token', querystring.stringify(data), config)
    } catch (err) {
      return err;
    }
}
app.listen(port, () => {
    console.log(`Listening on port ${port}`);
});

0 ответов

Другие вопросы по тегам