Angular问题和“No'Access-Control-Allow-Origin'标题” - 使用OAuth 2,Passport,Express和Node

时间:2014-12-19 01:00:28

标签: angularjs node.js express cors passport.js

我有一个使用在节点上运行的OAuth 2的Web应用程序。使用EJS模板,我能够正确创建一个工作流,提示用户登录,进行身份验证,然后执行“GetUser”GET命令并将输出转储到屏幕上。最近我试图删除EJS,并希望让AnguarJS工作。

目前我已经删除了EJS并实现了Angular,但是角度很多奇怪的事情发生了,我无法弄清楚为什么!

当我的用户点击“登录”时,他们应该被带到他们使用OAuth 2登录的另一个网站。这个过程在带有EJS的Node上正常工作,但是在我的控制器加载角度时,加载了正确的部分,但是没有数据。使用Chrome DEV工具查看此过程,我看到以下错误

XMLHttpRequest cannot load http://website/oauth/authorize?... 
No 'Access-Control-Allow-Origin'     
header is present on the requested resource. 
Origin 'http://localhost:8080' is therefore not allowed access.

甚至更奇怪的是,在网络标签中我可以看到正确的请求网址!如果我将此URL复制并粘贴到另一个选项卡中,我的“GetUser”命令会执行,但随后节点崩溃并且我的页面失败。

我尝试过不同的浏览器,启用CORS和配置CORS。我知道问题在于Angular,因为我可以成功地使用与EJS相同的代码。我已将我的Angular代码放在下面,任何帮助都将不胜感激!

服务器端

app.js

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var config = require('./config.js')
var passport = require('passport');
var OAuth2Strategy = require('passport-oauth').OAuth2Strategy;
var session = require('express-session');

var index = require('./routes/index');
var login = require('./routes/login');
var logout = require('./routes/logout');

passport.serializeUser(function(user, done) {done(null, user);
});
passport.deserializeUser(function(obj, done) {done(null, obj);
});

// config
passport.use('Company', new OAuth2Strategy({
    authorizationURL: config.authorizationURL,
    tokenURL: config.tokenURL,
    clientID: config.clientID,
    clientSecret: config.clientSecret,
    callbackURL: config.callbackURL,
    passReqToCallback: true
},
function(req, accessToken, refreshToken, profile, done) {
    process.nextTick(function () {
        // store access token
        req.session.accessToken=accessToken;
        return done(null, profile);
    });
}
));

var app = express();
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({secret: 'secret'}))
app.use(passport.initialize());
app.use(passport.session());

// configure Express
app.get('/api/login', ensureAuthenticated, login.execute);
app.get('/api/logout', logout.execute);

app.get('/auth/company', 
passport.authenticate('company'), 
 function(req, res){
});

app.get('/auth/company/callback',
passport.authenticate('company', { failureRedirect: '/' }),
function(req, res) {
 console.log('comming back from company');   
 res.redirect('/api/login');
}); 


app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

function ensureAuthenticated(req, res, next) {
   if (req.isAuthenticated()) {
    return next();
    }
    res.redirect('/')
}

module.exports = app;

Login.js(路线)

var request = require('request');

exports.execute = function (req, res) {
    console.log(req.user);
    console.log(req.app.get('accessToken'));

    var accessToken = req.session.accessToken;
    console.log("accessToken in loginjs" + accessToken);
    if(accessToken){
        var options = {
        url: 'http://company/getCurrentUser',
        headers: {
            Authorization: 'bearer ' + accessToken
        }
        };
        request.get(options, function(error, response, body){
            if(error){
               console.log('login.js inside error' + error);
               res.json('login.js inside error' + error);
        return;
            }
            console.log(response);
            res.render('account', { user: response });
        });
    }else{
        res.render('account', { user: req.user });
    }   
}

WWW

var debug = require('debug')('myApp');
var app = require('../app');

app.set('port', process.env.PORT || 8080);

var server = app.listen(app.get('port'), function() {
  debug('Express server listening on port ' + server.address().port);
});

客户端

app.js(angular)##

angular.module('MyApp', ['ngCookies', 'ngResource', 'ngMessages', 'ngRoute', 'mgcrea.ngStrap'])
.config(['$locationProvider', '$routeProvider', function($locationProvider, $routeProvider) {
    $locationProvider.html5Mode(true);

    $routeProvider
    .when('/', {
        templateUrl: 'views/home.html',
        controller: 'MainCtrl'
    })
    .when('/login', {
        templateUrl: 'views/account.html',
        controller: 'LoginCtrl'
    })      
    .otherwise({
        redirectTo: '/'
    }); 
}]);

login.js控制器

angular.module('MyApp')
.controller('LoginCtrl', ['$scope', 'Auth', function($scope, Auth){
    var user = Auth.authorize();
    $scope.user=user;
    $scope.headingTitle='Logged in page';
}]);

auth.js服务

angular.module('MyApp')
.factory('Auth', ['$resource', function($resource){
    return $resource('/auth/company', null, 
    {
        'authorize': {method: 'GET'}
    });
}]);

home.html部分路由到公司Oauth2

<div class="container">
  <div class="panel panel-default">
    <div class="panel-body">
      <div class="text-center">
        <p><a href="/login">Login via Company</a></p>
      </div>
    </div>
  </div>
</div>  

account.html部分显示用户数据

<div>
  <h1>You are logged in.</h1>
  <a href="/">Go home</a><br>
  <a href="/api/logout">Logout</a><br>
  <p>Dumping User: {{user}}</p>
</div>

修改

我试过以下没有成功

var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
    res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-     Requested-With, Access-Control-Allow-Origin');
    res.header("Access-Control-Max-Age", "86400"); // 24 hours
    if ('OPTIONS' == req.method) {
        res.send(200);
    }
    else {
        next();
   }
};
var app = express();
app.use(allowCrossDomain);

编辑2:

我做了一些挖掘,并且还注意到Angular未列为启动第二个URL。几乎就像有角度一样,将回调URL重新路由为它自己的单独调用。我附上了下面的图片 Dev Tools for Chrome of returned calls

编辑3:

我继续努力,但无法弄清楚为什么Angular会剥离我的标题!任何额外的输入将不胜感激!

编辑4:

我发现通过将以下代码添加到“登录”按钮,我可以让网页加载路径而不是Angular。执行此操作并将链接指向/ auth / company而不是api / login后,我成功重定向到登录页面!

<div class="container">
  <div class="panel panel-default">
    <div class="panel-body">
      <div class="text-center">
        <p><a target="_self" href="/auth/company">Login via Company</a></p>
      </div>
    </div>
  </div>
</div>  

然而战斗继续,因为我登录后我被重定向到下面的图片 - 在节点内部我收到数据然而应用程序死了并且没有显示/帐户页面。 Page after coming back from Oauth 2 Authentication

2 个答案:

答案 0 :(得分:1)

您可以尝试在快递服务器中启用CORS

npm install cors

app.js

var cors = require('cors')
var app = express()

app.use(cors())

引用this link

答案 1 :(得分:0)

我从不使用$resource而是使用$http。您必须启用&#39; withCredentials&#39;根据客户的要求。我也认为你不需要if('OPTIONS' == req.method),因为我从来不需要这个。还有一点需要注意,您不能使用通配符域&#39; *&#39;凭证。您必须明确允许来源&#39; http://127.0.0.1:8080&#39;并确保你的cookie使用127而不是localhost(否则你会遇到cookie的问题)。

     var req = {
                    method:'POST',
                    url: 'users/login',
                    data: {
                    },
                    withCredentials:true

                };

                $http(req).then(function (response) {                       
                    if( response.data.success ){                           
                    }
                    if( response.data.error){                           
                    }
                });