【问题标题】:Getting rid of CORS policy error with MEAN stack app (hosted on Heroku)使用 MEAN 堆栈应用程序(托管在 Heroku 上)消除 CORS 策略错误
【发布时间】:2021-02-13 04:04:05
【问题描述】:

我已经在 MEAN stack 应用程序上工作了一段时间,在过去的一个月里,我一直在努力解决这个 CORS 政策错误:

“从源访问 的 XMLHTTPRequest 已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:'Access-Control-Allow-Origin' 已一个值:不等于提供的原点。”

我已经一些成功地让它在一些设备上工作。在我的 server.js 文件中的中间件函数中的请求/响应标头设置和与后端通信的服务中的 POST 请求搞乱之后,我已经让它在我的桌面(Windows 10)上工作,在我的 Ubuntu 操作系统上我的台式机、笔记本电脑 (Windows 10)、我朋友的 macbook 等。

但是,我的一些朋友设备上仍然存在 CORS 政策问题。哪些设备工作和哪些设备不工作似乎没有任何共同点(不同的操作系统工作和不工作,当它不工作时,它适用于所有浏览器)。

还可能值得注意的是,在出现 CORS 错误的设备上,我的应用页面右上角会显示“不安全”,而在它工作的设备上它被标记为安全。

我做过的事情:

  • 在我的 server.js 文件中导入了 cors 模块
  • 尝试使用 csp(内容安全策略)模块
  • 修改了对我的服务器的请求的标头
  • 修改了从服务器发送回客户端的响应的标头
  • 大量搜索和摆弄 CORS 策略设置

如果相关的话,我还使用护照和 bcrypt 进行用户身份验证。

这里是相关的 server.js 代码:

var express = require('express');
var cors = require('cors');
//var csp = require('content-security-policy');
var app = express();
var dotenv = require('dotenv');
dotenv.config();

var url = require('url');

var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session'); // should give us persistent sessions...
var passport = require('passport');
var ejs = require('ejs');
var bcrypt = require('bcrypt');
var flash = require('express-flash');
var mongoose = require('mongoose');
var path = require('path');
//const env = require('./src/environments/environment');
//const methodOverride = require('method-override')
//var initializePassport = require('passport-config');
var initializePassport = require('./passport-config');
// this completes passport authentication strategy
// passes passport, a function for finding a user by their username,
// and a function for finding a user by id to the initialize() function inside passport-config
// the authenticateUser function then uses these methods to get what it needs
var connurl = '';
if(process.env.NODE_ENV == 'development'){
  connurl = 'http://localhost:4200';
}
else{
  connurl = 'https://to-do-bentancock.herokuapp.com';
}

initializePassport(
  passport,
  // both of these things are functions, passed into passport config
  // I think I pass mongoose middleware stuff here to return the right things
  username => Users.find({username: { $eq: username }}),
  id => Users.find({id: { $eq: id }})
)

var MongoStore = require('connect-mongo')(session);
var router = express.Router();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(cookieParser('process.env.SECRET'));

var cspPolicy = {
  'default-src': 'self, https://to-do-bentancock.herokuapp.com/*',
  'img-src': '*',
}

/*app.use(csp({
  policies: {
    'default-src': [csp.NONE],
    'img-src': [csp.SELF],
  }
}));

const globalCSP = csp.getCSP(cspPolicy);
app.use(globalCSP)

*/

app.use(session({
  secret: 'process.env.SECRET',
  resave: true, // should we reset our session variables if nothing has changed?
  // NOTE: this MUST be set to true otherwise the user authentication / session data won't be saved between middleware methods
  // e.g. if you log in (via /tasks post method), it will print the session data at the end, but if you then do '/create' method right after the req object will be null (because it wasn't saved)
  saveUninitialized: true, // do you want to save an empty value in the session if there is no value?
  cookie: {
    // might want to look into changing this in the future, as cookie stores user stuff
    // for now I have it off until I'm certain I've got all this passport js, cookie and session stuff down pat
    secure: false,
    maxAge: 600000
  },
  store: new MongoStore({
    mongooseConnection: mongoose.connection,
    ttl: 60 * 60, // keeps the session open for 1 hour
    collection: 'sessions'
  })
}));

app.use(passport.initialize());
app.use(passport.session());

app.use(cors({credentials: true, origin: true}));

// enables pre-flight requests across the board
app.options('*', cors()) // include before other routes

app.get('/with-cors', cors(), (req, res, next) => {
  console.log("testing cors:");
});

app.use('/', express.query());

app.get('/*', function(req,res) {
  res.header("Access-Control-Allow-Origin", connurl);
  res.header('Access-Control-Allow-Credentials', true);
  //res.header('Content-Type', 'application/json');
  console.log("here's what app.get is receiving: " + req.url);
  console.log("sending file!");
  res.sendFile(path.join(__dirname + '/dist/to-do-heroku/index.html'));
});

app.post('/loginCheck', function(req, res){
  res.header("Access-Control-Allow-Origin", connurl);
  res.header('Access-Control-Allow-Credentials', true);
  res.header('Content-Type', 'application/json');

  console.log("res header: %j", res.getHeaders());
  console.log("\nlogin check");
  if(req.isAuthenticated()){
    console.log("authentication returns true!");
    //console.log("printing req passport data: ");
    //console.log(req.session);
    //console.log(req.user);
    //res.headersSent();
    res.send({authenticated: true});
  }
  else{
    console.log("user is not authenticated");
    res.send({authenticated: false});
  }
});

app.post('/login', function(req, res, next) {
  res.header("Access-Control-Allow-Origin", connurl);
  res.header('Access-Control-Allow-Credentials', true);
  res.header('Content-Type', 'application/json');
  console.log("res header: %j", res.getHeaders());
  passport.authenticate('local', function(err, user, info) {
    console.log("printing error: " + err);
    console.log("passport info: " + JSON.stringify(info)); // undefined
    if(err){
      console.log("error authenticating!");
      res.send({status: 'error logging in user'});
      return;
    }

    if(!err){
      req.logIn(user, function(err){
        if(err){
          console.log("error logging in");
          //return
        }
        res.send({status: 'success'});
      });
    }
  })(req, res, next);
});

app.post('/logout', checkAuthenticated, async function(req, res){
  res.header("Access-Control-Allow-Origin", connurl);
  res.header('Access-Control-Allow-Credentials', true);
  res.header('Content-Type', 'application/json');
  console.log("\nlogging out user");
  await req.logout(); // logOut or logout??
  res.send({status: 'redirect', url: '/login'});
});


app.post('/getTasks', checkAuthenticated, function(req, res){
    res.header("Access-Control-Allow-Origin", connurl);
    res.header('Access-Control-Allow-Credentials', true);
    res.header('Content-Type', 'application/json');
    console.log("\n Successful authentication, request: " + JSON.stringify(req.body));

    Users.find({id: { $eq: req.session.passport.user}}, function(err, doc){
      if(!doc.length || doc == null){ // if the user is not found
        console.log("ERROR: USER NOT FOUND, LOGGING OUT");
        req.logOut();
        res.send({error:'not found'}); // send some kind of message back to client-side
      }
      else{
        res.send({tasks: doc[0].tasks, idCount: doc[0].idCount});
      }

    });
});



var uri = '';
if(process.env.NODE_ENV == 'development'){
  uri = 'mongodb://localhost/todoDB'
}
else{
  uri = "mongodb+srv://todoApp:7211@cluster0.huawl.mongodb.net/toDoDB?retryWrites=true&w=majority";
}


//const uri = "mongodb+srv://todoApp:7211@cluster0.huawl.mongodb.net/toDoDB?retryWrites=true&w=majority";
mongoose.connect(uri);
const connection = mongoose.connection;
connection.once('open', function(){
  mongoose.connection.db.collection('usersCollection').countDocuments(function(err, docs){
    console.log("there are " + docs + " docs in the collection\n");
  });
  console.log("MongoDB database connection established successfully\n");
});

function checkAuthenticated(req, res, next) {
  if (req.isAuthenticated()) {
    console.log("user is authenticated!");
    return next();
  }
  console.log("WARNING: USER NOT AUTHENTICATED");
  res.send({authenticated: false});
}

function checkNotAuthenticated(req, res, next) {
  if (req.isAuthenticated()) {
    console.log("\nuser IS authenticated, stopping this request...");
    // Send a message back to the client telling it to redirect instead
    //res.send({authenticated: true});
    return;
  }
  //res.send({authenticated: false});
  console.log("user is NOT authenticated");
  next();
}



if(process.env.NODE_ENV == 'development'){
  app.listen(4000, function(req, res){
    console.log("express server listening on port 4000");
  });
}
else{
  app.listen(process.env.PORT || 8080, function(req, res){
    console.log("express server listening on port 8080");
  });

}


这是与 server.js 通信的服务的代码:

auth.service:

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Router, ActivatedRoute, ParamMap } from '@angular/router';
import { Subject } from 'rxjs';
import { environment } from './../environments/environment';


@Injectable({
  providedIn: 'root'
})
export class AuthService {

  url = environment.apiUrl;


  username;
  password;
  loggedIn = false;



  constructor(private http: HttpClient, private router: Router) { }

  login(uname, pw){
    console.log("logging in user: " + uname + " " + pw + '\n');
    console.log("the url: " + this.url);
    this.username = uname;
    this.password = pw;
    return this.http.post(this.url + '/login', {username: uname, password: pw}, {
      headers: new HttpHeaders({
        'Access-Control-Allow-Credentials' : 'true',
        'Access-Control-Allow-Origin': "*" // this might just need to be the api url
      }),
      withCredentials: true
    });
  }

  setLogin(bool){
    this.loggedIn = bool;
  }

  logout(){
    console.log("test auth logout");
    return this.http.post(this.url + '/logout', {body: 'logout'},  {
      headers: new HttpHeaders({
        'Content-Type' : 'application/json',
        'Access-Control-Allow-Credentials' : 'true',
        'Access-Control-Allow-Origin': "*"
      }),
      withCredentials: true
    });
  }

  loginCheck(){
    console.log("test auth service login check");
    return this.http.post(this.url + '/loginCheck', {
      headers: new HttpHeaders({
        'Content-Type' : 'application/json',
        'Access-Control-Allow-Credentials' : 'true',
        'Access-Control-Allow-Origin': "*"
      }),
      withCredentials: true
    });
  }


  registerUser(uname, pw){
    console.log("registering user: " + uname + " " + pw + '\n');

    // the object sent needs to be a user object, which contains task objects
    // new user won't have any tasks tho (obvi)
    // also need to check for duplicate usernames
    return this.http.post(this.url + '/register',
    {
      username: uname,
      password: pw,
      idCount: 0,
      id: Date.now().toString(),
      tasks: []
    },
    {
      headers: new HttpHeaders({
        'Content-Type' : 'application/json',
        'Access-Control-Allow-Credentials' : 'true',
        'Access-Control-Allow-Origin': "*"
      }),
      withCredentials: true
    });
  }


  // takes user tasks data as input, passes it to tasks component
  renderTasks(){
    console.log("render tasks \n");
    this.router.navigate(['/tasks']);
  }

task.service:

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { catchError, tap, share, map } from 'rxjs/operators';
import { environment } from './../environments/environment';

@Injectable({
  providedIn: 'root'
})
export class TasksService {
  //url = 'http://localhost:4000' // the port the mongo database is listening on
  //url = 'https://to-do-bentancock.herokuapp.com';
  url = environment.apiUrl;
  constructor(private http: HttpClient) { }


  getTasks(userName, pw){
    console.log("tasks service: get tasks \n");
    console.log("username and pw to post: " + userName + " " + pw);

    return this.http.post(this.url + '/getTasks', {username: userName, password: pw},
    {
      headers: new HttpHeaders({
        'Content-Type' : 'application/json',
        'Access-Control-Allow-Credentials' : 'true',
        'Access-Control-Allow-Origin': "*"
      }),
      withCredentials: true
    });
  }

  deleteTask(uname, pw, id: number ){
    var delUrl = this.url + "/deleteTask/" + id;

    return this.http.post(delUrl, {username: uname, password: pw},
      {
        headers: new HttpHeaders({
          'Content-Type' : 'application/json',
          'Access-Control-Allow-Credentials' : 'true',
          'Access-Control-Allow-Origin': "*"
        }),
        withCredentials: true
      }
    );

  }

  /*
  a task object has a:
  - name
  - date
  - description
  - priority
  - id
  */
  createTask(uname, pw, task){
    console.log("test create task (service)");

    // send user data, and a task object
    return this.http.post(this.url + '/create',
    {
      task:
      {
        name: task.name,
        date: task.date,
        description: task.description,
        priority: task.priority,
        id: task.id,
        state: task.state
      },
      user:
      {
        username: uname,
        password: pw
      }
    },
    {
      headers: new HttpHeaders({
        'Content-Type' : 'application/json',
        'Access-Control-Allow-Credentials' : 'true',
        'Access-Control-Allow-Origin': "*"
      }),
      withCredentials: true
    }
  );
  }

我一直在谷歌上搜索并排除故障,我已经筋疲力尽了。有人有建议吗?我错过了什么?

【问题讨论】:

    标签: node.js angular typescript express cors


    【解决方案1】:

    我只是在你的 get 中使用 app.use(cors()) 而没有 app.options('*', cors())cors()

    【讨论】:

      猜你喜欢
      • 2020-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-09
      • 1970-01-01
      • 2018-11-08
      • 1970-01-01
      • 2020-11-06
      相关资源
      最近更新 更多