在静态 Web 应用程序的 Azure 函数中实现 Passport.js 的 CORS 问题。护照returns 401

CORS problem with Passport.js implemented in Azure Function in Static Web App. Passport returns 401

我正在开发一个使用 Azure 静态 Web 应用产品的项目。我已经实施了由 azure-function-express 提供支持的 Passport.js 身份验证策略,它在身份验证 header 中接收 JWT,验证 JWT,并 returns 用户信息。

我的系统在本地工作,但是 returns 401 在部署中未经授权。

在部署中进行测试时,Application Insights 推断资源因 CORS 问题而被阻止,但未指定是哪个资源。尽管存在 CORS 问题,该函数似乎仍在执行,但 returns 一个 401,即使测试帐户信息是正确的。

有没有人遇到过这个问题或知道如何确定哪个资源被 CORS 阻止了?

Browser Error

Azure Live Analytics -- 抱歉,为了便于阅读,这些内容无法完全展开

CORS 消息展开

请求的来源header:'https://icy-plant-mysiteID.centralus.azurestaticapps.net'。

CORS 策略执行失败。

请求源https://icy-plant-mysiteID.centralus.azurestaticapps.net没有访问资源的权限。

GetUserFromJwt Azure 函数

const passport = require('passport');
const createHandler = require("azure-function-express").createHandler;
const express = require("express");
const app = express();
const mongooseHelper = require('../config/mongoose');


// Configure passport, express
require('../config/passport')(passport);
require('../config/express')(app, passport);

mongooseHelper.connectToMongoose("GetUserIdFromJwt");

app.get('/api/getUserIdFromJwt', passport.authenticate('jwt', { session: false }), (req, res, next) => {
  res.status(200).json(req.user)
});

// Binds the express app to an Azure Function handler
module.exports = createHandler(app);

API调用(客户端在获取JWT时调用)

export const getUserIdFromJwt = (jwt) => {
  return new Promise((resolve, reject) => {
    axios({
      url: '/api/getUserIdFromJwt',
      method: 'GET',
      headers: { "Authorization": jwt }
    }).then((res) => {
      resolve(res.data)
    }).catch((err) => {
      reject(console.log("An error occured getting the User from JWT: " + err));
    });
  })
}

护照配置

// Configure Passport
const User = require('../models/UserModel');
const JwtStrat = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;

const PUB_KEY = **MY KEY**;


const passportOptions = {
  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
  secretOrKey: PUB_KEY,
  algorithms: ['OurAlgorithm'],
  passReqToCallback: true
}

const strat = new JwtStrat(passportOptions, (req, payload, done) => {
  User.findOne({ _id: payload.sub })
    .then((user) => {
      if (user) {
        // Send id as User. Do not send personal info here.
        req.user = {id: payload.sub, role: payload.role}; 
        return done(null, req.user);
      } else {
        return done(null, false);
      }
    })
    .catch(err => {
      done(err, null)
    });
});

module.exports = (passport) => {
  passport.use(strat);
}

快速配置

const express = require('express')
const cors = require('cors');


module.exports = (app, passport) => {
  app.use(express.json());
  app.use(express.urlencoded({ extended: false }));
  app.use(cors());
  app.use(passport.initialize());
}

问题请参考以下步骤

  1. 创建 Azure 函数

  2. Configure CORS for Azure function

  3. 代码。我使用 Azure Cosmos DB Mongo API 来保存用户。您可以访问here阅读我的功能代码

护照配置

const passportJWT = require("passport-jwt");
const User = require("../Models/UserModel");

// passport & jwt config
const { Strategy: JWTStrategy, ExtractJwt: ExtractJWT } = passportJWT;

// define passport jwt strategy
const opts = {};
opts.jwtFromRequest = ExtractJWT.fromAuthHeaderWithScheme("jwt");
opts.secretOrKey =
  "QOOC3nUVl9yTZiH2F0VYjOJhwm2ZkyBjWK7Mzo4bH54cNBBUQmp262S0Tx1eBBTT";
opts.algorithms = ["HS256"];
const passportJWTStrategy = new JWTStrategy(opts, function (jwtPayload, done) {
  // retreive mail from jwt payload
  const email = jwtPayload.email;
  User.findOne({ email: email }, (error, user) => {
    if (error) {
      return done(error, false);
    } else {
      if (user) {
        done(null, user);
      } else {
        done(null, false);
      }
    }
  });
});

// config passport
module.exports = function (passport) {
  // token strategy
  passport.use(passportJWTStrategy);

  // return configured passport
  return passport;
};

GetUserFromJwt Azure 函数

const passport = require("passport");
const bodyParser = require("body-parser");
const createHandler = require("azure-function-express").createHandler;
const express = require("express");
const app = express();

// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));

// parse application/json
app.use(bodyParser.json());

// init and configure passport
app.use(passport.initialize());

// Configure passport
require("../config/passport")(passport);

require("../config/mongo")
  .connect()
  .catch((error) => {
    throw error;
  });

app.get(
  "/api/getUserIdFromJwt",
  passport.authenticate("jwt", { session: false }),
  (req, res, next) => {
    res.status(200).json(req.user);
  }
);

// Binds the express app to an Azure Function handler
module.exports = createHandler(app);

4 创建 jwt 令牌

const jwt = require("jsonwebtoken");
const  secretOrKey =
  "QOOC3nUVl9yTZiH2F0VYjOJhwm2ZkyBjWK7Mzo4bH54cNBBUQmp262S0Tx1eBBTT";
const  token = jwt.sign(<your playlaod>, secretOrKey , { algorithm: 'HS256' });
const jwt= `JWT ${token}`
  1. 在 Postman 中测试
GET https://testjsfun.azurewebsites.net/api/getUserIdFromJwt

Authorization : JWT <token>

我在联系 Microsoft 技术支持后发现了这个问题。

Microsoft 提供的静态 Web 应用程序服务在内部使用授权 header,因此通过授权 header 发送到函数的令牌被修改或覆盖。通过使用不同的 header.

发送 JWT 解决了这个问题