使用Netlify Lambda函数通过Auth0验证Firebase

使用Netlify Lambda函数通过Auth0验证Firebase,firebase,lambda,auth0,Firebase,Lambda,Auth0,我有一个用Gatsby构建的web应用程序,它通过Auth0进行客户端身份验证。我想将Firebase用作我的项目的数据库,但我需要先对用户进行身份验证,然后他们才能读/写Firebase Firebase SDK(Firebase admin)有一个名为signInWithCustomToken(token)的函数,我以为可以将令牌从Auth0传递到该函数中,但这不起作用(请参阅:) 相反,我需要通过一个API代理Auth0的令牌,该API将使用firebase admin发布令牌。因为我的盖

我有一个用Gatsby构建的web应用程序,它通过Auth0进行客户端身份验证。我想将Firebase用作我的项目的数据库,但我需要先对用户进行身份验证,然后他们才能读/写Firebase

Firebase SDK(Firebase admin)有一个名为signInWithCustomToken(token)的函数,我以为可以将令牌从Auth0传递到该函数中,但这不起作用(请参阅:)

相反,我需要通过一个API代理Auth0的令牌,该API将使用firebase admin发布令牌。因为我的盖茨比网站托管在Netlify上,所以我计划使用Netlify Lambda函数获取代理Auth0的令牌。这就是我被卡住的地方

我按照本教程介绍了如何在Gastsby中使用Netlify Lambda函数:

然后,我进入Auth.js文件,其中包含Auth0代码,并在setSession中放弃了一个fetch调用。我将idToken从Auth0传递到fetch函数中的url中。我不确定这样做是否正确。我在教程中读到,它将在授权头中传递,但我不清楚这意味着什么。无论如何,下面是完整的auth.js文件:

import auth0 from 'auth0-js';

const windowGlobal = typeof window !== 'undefined' && window;

class Auth {
  auth0 = new auth0.WebAuth({
    domain: process.env.Auth_Domain,
    clientID: process.env.Auth_ClientId,
    redirectUri: process.env.Auth_Callback,
    responseType: 'token id_token',
    scope: 'openid profile email',
  });

  constructor() {
    this.login = this.login.bind(this);
    this.logout = this.logout.bind(this);
    this.handleAuthentication = this.handleAuthentication.bind(this);
    this.isAuthenticated = this.isAuthenticated.bind(this);
  }

  login() {
    this.auth0.authorize();
  }

  logout() {

    // Remove the locally cached profile to avoid confusing errors.
    localStorage.removeItem('access_token');
    localStorage.removeItem('id_token');
    localStorage.removeItem('expires_at');
    localStorage.removeItem('user');

    windowGlobal.window.location.replace(`https://login.skillthrive.com/v2/logout/?returnTo=http%3A%2F%2Flocalhost:8000`)

  }

  handleAuthentication() {
    if (typeof window !== 'undefined') {
      this.auth0.parseHash((err, authResult) => {
        if (authResult && authResult.accessToken && authResult.idToken) {
          this.setSession(authResult)
        } else if (err) {
          console.log(err);
        }
      });
    }
  }

  isAuthenticated() {
    const expiresAt = JSON.parse(localStorage.getItem('expires_at'));
    return new Date().getTime() < expiresAt;
  }

  setSession(authResult) {
    const expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime());
    localStorage.setItem('access_token', authResult.accessToken);
    localStorage.setItem('id_token', authResult.idToken);
    localStorage.setItem('expires_at', expiresAt);

    fetch(`/.netlify/functions/firebase?id=${authResult.idToken}`)
    .then(response => console.log(response))

    this.auth0.client.userInfo(authResult.accessToken, (err, user) => {
      localStorage.setItem('user', JSON.stringify(user));
    })
  }

  getUser() {
    if (localStorage.getItem('user')) {
      return JSON.parse(localStorage.getItem('user'));
    }
  }

  getUserName() {
    if (this.getUser()) {
      return this.getUser().name;
    }
  }

}

export default Auth;
我试图一次将小部分合并到Lambda函数中:

var admin = require("firebase-admin");
const jwt = require('express-jwt');
const jwks = require('jwks-rsa');

// For more info, check https://www.netlify.com/docs/functions/#javascript-lambda-functions
export function handler(event, context, callback) {
  console.log("queryStringParameters", event.queryStringParameters);

  const jwtCheck = jwt({
    secret: jwks.expressJwtSecret({
      cache: true,
      rateLimit: true,
      jwksRequestsPerMinute: 5,
      jwksUri: `https://${process.env.Auth_Domain}/.well-known/jwks.json`
    }),
    audience: process.env.Auth_Audience,
    issuer: `https://${process.env.Auth_Domain}/`,
    algorithm: 'RS256'
  });

  callback(null, {
    // return null to show no errors
    statusCode: 200, // http status code
    body: JSON.stringify({
      msg: "Hello, World! " + Math.round(Math.random() * 10),
    }),
  })
}
我试图通过控制台记录jwtCheck来查看它返回了什么,但我得到的只是一些奇怪的东西
{[Function:d],除非:[Function],UnauthorizedError:[Function:r]}

如何将其合并到Lambda函数中?

我发现了一个名为的模块,它允许我编写Lambda函数,就像它是用Express编写的一样。这让我很容易理解正在发生的事情,因此我最终获得了从Firebase返回新铸造令牌的代码:

const jwt = require('express-jwt');
const jwks = require('jwks-rsa');
const firebaseAdmin = require('firebase-admin');
// Config
const config = require('./config');

module.exports = function(app) {
  // Auth0 athentication middleware
  const jwtCheck = jwt({
    secret: jwks.expressJwtSecret({
      cache: true,
      rateLimit: true,
      jwksRequestsPerMinute: 5,
      jwksUri: `https://${config.AUTH0_DOMAIN}/.well-known/jwks.json`
    }),
    audience: config.AUTH0_API_AUDIENCE,
    issuer: `https://${config.AUTH0_DOMAIN}/`,
    algorithm: 'RS256'
  });

  // Initialize Firebase Admin with service account
  const serviceAccount = require(config.FIREBASE_KEY);
  firebaseAdmin.initializeApp({
    credential: firebaseAdmin.credential.cert(serviceAccount),
    databaseURL: config.FIREBASE_DB
  });

app.get('/auth/firebase', jwtCheck, (req, res) => {
    // Create UID from authenticated Auth0 user
    const uid = req.user.sub;
    // Mint token using Firebase Admin SDK
    firebaseAdmin.auth().createCustomToken(uid)
      .then(customToken => 
        // Response must be an object or Firebase errors
        res.json({firebaseToken: customToken})
      )
      .catch(err => 
        res.status(500).send({
          message: 'Something went wrong acquiring a Firebase token.',
          error: err
        })
      );
  });
const express = require('express');
const serverless = require('serverless-http');
const cors = require('cors');
const jwt = require('express-jwt');
const jwks = require('jwks-rsa');
const firebaseAdmin = require('firebase-admin');

const app = express();
app.use(cors());

const jwtCheck = jwt({
  secret: jwks.expressJwtSecret({
    cache: true,
    rateLimit: true,
    jwksRequestsPerMinute: 5,
    jwksUri: `${process.env.Auth_Domain}/.well-known/jwks.json`
  }),
  audience: `${process.env.Auth_ClientId}`,
  issuer: `${process.env.Auth_Domain}`,
  algorithm: 'RS256'
});

const serviceAccount = require('../firebase/firebase-keys.json');

firebaseAdmin.initializeApp({
  credential: firebaseAdmin.credential.cert(serviceAccount),
  databaseURL: `https://${serviceAccount.project_id}.firebaseio.com`
});

  // GET object containing Firebase custom token
  app.get('/firebase', jwtCheck, async (req, res) => {
    const {sub: uid} = req.user;

    try {
      const firebaseToken = await firebaseAdmin.auth().createCustomToken(uid);
      res.json({firebaseToken});
    } catch (err) {
      res.status(500).send({
        message: 'Something went wrong acquiring a Firebase token.',
        error: err
      });
    }
  });

module.exports.handler = serverless(app);

然后在客户端,我将fetch调用包装成如下函数,并在需要时使用它:

  async setFirebaseCustomToken() {
    const response = await fetch('/.netlify/functions/firebase', {
      headers: {
        'Authorization': `Bearer ${localStorage.getItem('id_token')}`,
      },
    });

    const data = await response.json();
    console.log(data.firebaseToken);
  }

这段代码只是将新令牌记录到console.log中,但现在您将得到响应,可以在Firebase客户端执行您想要的操作。希望这有帮助