【发布时间】:2016-08-06 15:54:13
【问题描述】:
最近我们决定将前端从 EJS 切换到 Angular,将前端和后端完全分开。在这样做的过程中,我们开始在多个浏览器中遇到几个问题。在后端,我们使用带有 express 的 Node 以及护照和 oauth2。对于前端,我们尝试使用 angular。 EJS 使用 express.render 工作,但我们更喜欢直接使用 angular,将 express 用作 RESTful API。
尊敬的,我在 localhost:8080 和 localhost:3000 本地运行后端和前端。当只使用后端(使用 EJS,而不是 ANGULAR)时,我可以成功地在浏览器中转到我们的后端端口,通过 passport-oauth 登录,然后重定向到我的 json 数据所在的帐户页面(从提供商登录屏幕)通过 res.json 呈现。问题是删除 EJS 后我无法从前端 UI 执行此操作。
我在使用三种不同的浏览器时尝试了十几种不同的方式来配置 CORS,但都没有成功。以下三个 sn-ps 是我在尝试通过 $http 和 $resource 从前端访问 localhost:8080 时在浏览器控制台中遇到的错误(代码见下文)。三个代码 sn-ps 下面的图像是节点控制台在尝试从每个不同的浏览器访问端口 8080 时告诉我的...
铬:
XMLHttpRequest cannot load 'PROVIDER-DETAILS-URL'. No 'Access-Control-Allow- Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
火狐:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at 'PROVIDER-DETAILS-URL'. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at 'PROVIDER-DETAILS-URL'. (Reason: CORS request failed).
Safari:
XMLHttpRequest cannot load http://localhost:8080/auth/PROVIDER. Request header field Accept-Encoding is not allowed by Access-Control-Allow-Headers.
还有代码:
服务器:
app.js
'use strict';
const express = require('express');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const logger = require('morgan');
const errorHandler = require('errorhandler');
const path = require('path');
const flash = require('connect-flash');
const passport = require('passport');
const expressValidator = require('express-validator');
/**
* Load environment variables, where API keys and passwords are configured.
*/
const config = require('./config/config');
/**
* Route Handlers
*/
const index = require('./routes/index');
const account = require('./routes/account');
const logout = require('./routes/logout');
/**
* API keys and Passport configuration.
*/
const passportConfig = require('./strategy');
/**
* Create Express server.
*/
const app = express();
/**
* Express configuration.
*/
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
res.header("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT");
next();
});
app.use(cookieParser());
app.use(expressValidator());
app.use(session({
resave : true,
saveUninitialized : true,
secret : config.sessionSecret,
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
/**
* Primary app routes.
*/
app.get('/', index.execute);
app.get('/account', passportConfig.isAuthenticated, account);
app.get('/logout', logout.execute);
/**
* OAuth authorization routes.
*/
app.get('/auth/PROVIDER', passport.authenticate('PROVIDER'));
app.get('/auth/PROVIDER/callback', passport.authenticate('PROVIDER', { failureRedirect : '/'}), function(req, res) {
res.redirect('/account');
});
/**
* Error Handler.
*/
app.use(errorHandler());
/**
* Start Express server.
*/
app.listen(8080, () => {
console.log('App listening on port 8080');
});
module.exports = app;
strategy.js
'use strict';
const passport = require('passport');
const session = require('express-session');
const config = require('./config/config');
const OAuth2Strategy = require('passport-oauth').OAuth2Strategy;
/**
* Put together the right header info for PROVIDER
*/
var authString = new Buffer(config.PROVIDER.clientID + ':' + config.PROVIDER.clientSecret);
var customHeader = {
"Authorization": "Basic " + authString.toString('base64')
};
/**
* OAuth2Strategy containing the customHeader created above.
*/
passport.use('PROVIDER', new OAuth2Strategy({
authorizationURL : config.PROVIDER.authorizationURL,
tokenURL : config.PROVIDER.tokenURL,
clientID : config.PROVIDER.clientID,
clientSecret : config.PROVIDER.clientSecret,
callbackURL : config.PROVIDER.callbackURL,
customHeaders : customHeader,
passReqToCallback : true
},
function( req, accessToken, refreshToken, profile, done ) {
req.session.accessToken = accessToken;
return done(null, profile);
}
));
passport.serializeUser(function(user, done) {
return done(null, user);
});
passport.deserializeUser(function(obj, done) {
return done(null, obj);
});
/**
* Login Required middleware.
*/
exports.isAuthenticated = function(req, res, next) {
if (req.isAuthenticated()) {
console.log('isAuthenticated');
return next();
}
res.redirect('/');
};
/**
* Authorization Required middleware.
*/
exports.isAuthorized = function(req, res, next) {
var provider = req.path.split('/').slice(-1)[0];
if (_.find(req.user.tokens, { kind: provider })) {
next();
} else {
res.redirect('/auth/' + provider);
}
};
index.js
exports.execute = function (req, res) {
if (req.user) {
console.log('========== ROUTES/INDEX.JS | 3 ==========');
res.redirect('/account');
} else {
console.log('========== ROUTES/INDEX.JS | 6 ==========');
res.redirect('/auth/PROVIDER');
}
};
客户:
我把它结合起来使它更容易阅读。
angular.module('StackOverflowPost', [])
.factory('APIService', function() {
function getData( $q, $http ) {
var defer = $q.defer();
$http.get( 'localhost:8080' )
.success( getDataComplete )
.catch( getDataFailed );
function getDataComplete( response ) {
console.log( response.Authorization );
defer.resolve(response.data.results );
}
function getDataFailed( error ) {
console.log( error.data );
defer.reject( 'XHR Failed for getData - ' + error.data );
}
return defer.promise;
}
})
.controller('MainCtrl', function( APIService ) {
var vm = this;
vm.getDataTest = function() {
APIService.getData().then(function( returnedData ) {
console.log( returnedData );
})
}
});
任何帮助或指导将不胜感激。
更新 (2016 年 4 月 28 日):我用更多细节更新了原始帖子。经过一周的反复试验,我还更新了代码。
【问题讨论】:
标签: angularjs node.js express oauth cors