尝试在API服务器上使用jwt进行身份验证时出现问题

时间:2020-01-08 12:53:40

标签: node.js reactjs express cors jwt

我正在构建一个可以处理各种请求的后端api和一个前端,以便用户一旦登录就可以在日历中看到请求。前端和后端都运行在单独的nodejs Express Web服务器上。为了部署React前端,我运行一个npm run build,然后将build文件夹的内容复制到前端服务器的公共文件夹中。这可能不是部署React WebApp的正确方法吗?

无论如何,在localhost上运行都很好,但是一旦我尝试将其部署为两个独立的heroku应用程序,就会出现cors问题,而且我不知道如何解决它。

我得到的cors错误是:

跨源请求被阻止:同源策略禁止阅读 https://example.com/request/allApproved上的远程资源。 (原因:CORS标头“ Access-Control-Allow-Origin”缺失)。

文件结构如下: 后端:

src
 |- public
  |- controller
   |- various repositories.js files
  |- models
   |- mongodb model.js files
  |- router
   |- routes for the repositories.
 |- .env
 |- app.js
 |- dbParser.js
 |- passportSetup.js

我在app.js中有我的cors设置,如下所示:

require("dotenv").config();
const express = require("express");
const MongoDBStore = require("connect-mongo")(session);
const Mongoose = require("./dbParser");
var User = require("./public/models/user");
var cors = require("cors");
var Request = require("./public/models/request");
const passport = require('passport');
require('./passportSetup')(passport);
const jwt = require('jsonwebtoken');
const LocalStrategy = require('passport-local').Strategy;
const passportJWT = require('passport-jwt');
const JWTStrategy = passportJWT.Strategy;

// allow localhost and heroku frontend url.
var allowedOrigins = [process.env.DEVELOPMENT_ORIGIN, process.env.LIVE_FRONT];
app.use(cors({
  origin: function(origin, callback){    
    // allow requests with no origin 
    // (like mobile apps or curl requests)
    if(!origin) return callback(null, true);

    if(allowedOrigins.indexOf(origin) === -1){
      var msg = 'The CORS policy for this site does not ' +
                'allow access from the specified Origin.';
      return callback(new Error(msg), false);
    }    return callback(null, true);
  },
  credentials: true
}));

app.post("/login", (req, res) => {
    User.findOne({ email: req.body.email.toLowerCase() }, function(err, user) {
      if (err || user == null) {
        console.log('wrong username')
        res.status(401).json({
            error: 'wrong credetials'
        });
      } else {
        if (user.validPassword(req.body.password)) {
          //console.log(user.toJSON())
          let token = jwt.sign(user.toJSON(), 'secret', {
            expiresIn: 604800 // 1 week

          });
          res.status(200).json({success: true, jwt: 'jwt ' + token});
        } else {
          res.status(402).json({
            login: 'noo'
          });
        }
      }
    }); 
});

app.post("/authorize", passport.authenticate('jwt', { session: false}), (req, res) => {
  if (req.user.userId != undefined) {
    User.findOne({  }, function(err, user) {
      if (err || user == null) {
        res.sendStatus(400);
      } else if(user){
        let filteredUser = {
          name: req.user.name,
          lastName: req.user.lastName,
          isAdmin: req.user.isAdmin,
          userId: req.user.userId,
          region: req.user.region,
          email: req.user.email
        };
        res.status(200).json(filteredUser);
      } else {
        res.sendStatus(401)
      }
    });
  } else {
    res.sendStatus(401);
  }
});

app.use("/user", passport.authenticate('jwt', {session: false}), userRoutes);
app.use("/request", passport.authenticate('jwt', {session: false}), requestRoutes);

app.all("*", (req, res) => {
  res.sendStatus(404);
});
app.listen(process.env.PORT || 8080);

在React前端中,我使用axios来调用我的api

const login = (email: string, password: string): any => axios(`${process.env.REACT_APP_API_URL}/login`, {
    method: "POST",
    withCredentials: true,
    data: { email, password }
});

const allApprovedVacReqs = (): any => axiosWrapper(`${process.env.REACT_APP_API_URL}/request/allApproved`, {
    method: "GET",
    withCredentials: true,
    headers: {
        Authorization: localStorage.getItem('jwt'),
    }
});

requestRoutes.js(放置在路由文件夹中)

var express = require("express");
var router = express.Router();
const requestRepository = require('../controller/requestRepository')

router.route('/allPending').get(requestRepository.getAllPending)
router.route('/allDenied').get(requestRepository.getAllDenied)

router.route('/allApproved').get(requestRepository.getAllApproved)

module.exports = router;

我知道jwt可能不应该存储在本地存储中,但是在注销时将其删除,并且出于我的目的,可能还可以。

放置从npm run build获得的文件的nodejs服务器

const express = require('express')
const app = express()
const port =  process.env.PORT || 3000
const path = require('path')
app.use(express.static(path.join(__dirname, 'public')))

app.use(function(req, res, next) {
    res.set('Access-Control-Allow-Credentials', true);
    next();
  });

app.get('*', (req, res) =>{
    res.sendFile(path.join(__dirname+ '/public/index.html'))
})
app.listen(port, () => console.log(`frontend listening on port ${port}!`))

我可以正常登录,但是当我尝试访问路由/ request / allApproved并将jwt传递到标题时,我遇到了麻烦。

我非常感谢您对如何解决此问题的任何想法。

0 个答案:

没有答案