Node.js 使用MEAN stack应用程序消除CORS策略错误(托管在Heroku上)
我在一个MEAN stack应用程序上工作了一段时间,在过去的一个月里,我一直在努力解决这个CORS策略错误: “从源站访问XMLHTTPRequest已被CORS策略阻止:对飞行前请求的响应未通过访问控制检查:'访问控制允许源站'的值不等于提供的源站。” 我已经在一些设备上取得了一些成功。在我的server.js文件中的中间件函数中的请求/响应头设置和在与后端通信的服务中发布请求后,我已经让它在我的桌面(Windows 10)、我的桌面上的Ubuntu操作系统、我的笔记本电脑(Windows 10)、我的朋友macbook等上工作 然而,我仍然在我朋友的一些设备上遇到CORS策略问题。什么设备工作和什么设备不工作似乎没有任何共同之处(不同的操作系统工作和不工作,当它不工作时,它跨所有浏览器) 可能还值得注意的是,在出现CORS错误的设备上,我的应用程序页面右上角显示“不安全”,而在它工作的设备上,则标记为安全 我做过的事情:Node.js 使用MEAN stack应用程序消除CORS策略错误(托管在Heroku上),node.js,angular,typescript,express,cors,Node.js,Angular,Typescript,Express,Cors,我在一个MEAN stack应用程序上工作了一段时间,在过去的一个月里,我一直在努力解决这个CORS策略错误: “从源站访问XMLHTTPRequest已被CORS策略阻止:对飞行前请求的响应未通过访问控制检查:'访问控制允许源站'的值不等于提供的源站。” 我已经在一些设备上取得了一些成功。在我的server.js文件中的中间件函数中的请求/响应头设置和在与后端通信的服务中发布请求后,我已经让它在我的桌面(Windows 10)、我的桌面上的Ubuntu操作系统、我的笔记本电脑(Windows
- 已在my server.js文件中导入cors模块
- 尝试使用csp(内容安全策略)模块
- 修改了发送到我的服务器的请求的标题
- 修改了从服务器发送回客户端的响应的标题
- 大量的谷歌搜索和摆弄CORS策略设置
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通信的服务的代码:
身份验证服务:
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']);
}
任务.服务:
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
}
);
}
我一直在用谷歌搜索并解决这个问题,我已经筋疲力尽了。有人有什么建议吗?我遗漏了什么?我只是在使用app。在get中使用(cors())
而不使用app.options('*',cors())
和cors()