CORS 403 error Angular and Express

2019-07-18 05:32发布

问题:

Part of my Express configuration looks like this and runs on different domain

app.use(function(req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", 'http://localhost:3000');
    res.setHeader("Access-Control-Allow-Credentials","true");
    res.setHeader("Access-Control-Expose-Headers", "Set-Cookie");
    res.setHeader("Access-Control-Allow-Headers", "Content-Type, x-xsrf-token, X-Requested-With, Accept, Expires, Last-Modified, Cache-Control");
    res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE");
    next();
});
app.configure('development', 'production', function() {
    app.use(express.csrf());
    app.use(function(req, res, next) {
        res.cookie('XSRF-TOKEN', req.csrfToken());
        next();
    });
});

When using CORS there is OPTIONS request before anything different than a GET. The server is manually configured to respond to it with 200 every time, so it proceed to the POST or whatever. The requests come from Angular. Some said I need to add some of these lines in order to configure Angular properly.

$httpProvider.defaults.xsrfCookieName = 'XSRF-TOKEN';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
$httpProvider.defaults.useXDomain = true;
$httpProvider.defaults.withCredentials = true;

The error which I get is 403 Forbidden, the only solution so far is to comment out the whole app.configure(..) in the server. Obviously, I have some problem with CSRF and I cannot understand what should I do.

EDITED

回答1:

This section of the doc says that

For requests without credentials, the server may specify "*" as a wildcard, thereby allowing any origin to access the resource.

Wildcard is used for completely public APIs which don't require an auth. If you want to use credentials (via cookies) you've got to set the exact list of allowed urls in Access-Control-Allow-Origin

Make sure res.setHeader("Access-Control-Allow-Credentials","true"); is used at the back end like:

 app.use(function(req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", 'YOUR URL HERE');
    res.setHeader("Access-Control-Allow-Credentials","true");
    res.setHeader("Access-Control-Expose-Headers", "Set-Cookie");
    res.setHeader("Access-Control-Allow-Headers", "Content-Type, x-xsrf-token, X-Requested-With, Accept, Expires, Last-Modified, Cache-Control");
    res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
});

Also the $httpProvider.defaults.withCredentials = true; should be used at the angular side to allow sending the credentials.

angular.module('CoolModule')
  .config(['$httpProvider', function($httpProvider){
    // For Access-Control-Allow-Origin and Set-Cookie header
    $httpProvider.defaults.withCredentials = true;
  }]); 

or $http({withCredentials: true, ...}).get(...)

Hope this helps.

EDIT: Not a solution, but as a workaround to allow the OPTIONS request this piece of code could be added:

...
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
if ('OPTIONS' == req.method) { 
  res.send(200); } else { next(); 
}
...


回答2:

You need to enable CORS support your angular.js app:

yourApp.config(['$httpProvider', function($httpProvider) {
        $httpProvider.defaults.useXDomain = true;
        delete $httpProvider.defaults.headers.common['X-Requested-With'];
    }
]);


回答3:

This should sort you out.

var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Content-Type');

    next();
}

app.use(allowCrossDomain);