Angular 问题和“没有 'Access-Control-Allow-Origin' 标头” - 使用 OAuth 2、Passport、Express 和 Node

Posted

技术标签:

【中文标题】Angular 问题和“没有 \'Access-Control-Allow-Origin\' 标头” - 使用 OAuth 2、Passport、Express 和 Node【英文标题】:Angular issues and "No 'Access-Control-Allow-Origin' header" - Using OAuth 2, Passport, Express and NodeAngular 问题和“没有 'Access-Control-Allow-Origin' 标头” - 使用 OAuth 2、Passport、Express 和 Node 【发布时间】:2015-02-17 22:24:51 【问题描述】:

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

目前我已经删除了 EJS 并实现了 Angular,但是在 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!如果我将此 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.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。就好像 Angular 将回调 URL 重新路由为它自己的单独调用一样。我附上了下面的图片

编辑 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>  

但是战斗仍在继续,因为在我登录后我被重定向到下图 - 在节点内部我收到数据但是应用程序死了并且不显示 /account 页面。

【问题讨论】:

可能重复:***.com/questions/7067966/… 尝试第三个答案,最快的解决方案。阅读全文以了解它。 我已经在上面添加和编辑 - 我试了一下,但看到了相同的结果 我继续进行编辑,但我仍然找不到解决问题的方法! Angular 正在接管一些我还没有意识到的方面! Angular JS + Node JS + Passport + Spring OAuth2 Authentication/Authorization的可能重复 @Kent0111 这个问题你解决了吗?因为我有同样的问题。 【参考方案1】:

你可以尝试在 express 服务器中启用 CORS

npm install cors

app.js

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

app.use(cors())

参考this link

【讨论】:

【参考方案2】:

我从不使用$resource,而是使用$http。您还必须根据客户的请求启用“withCredentials”。我也认为你不需要if('OPTIONS' == req.method),因为我从来不需要这个。另请注意,您不能将通配符域“*”与凭据一起使用。您必须明确允许 origin 'http://127.0.0.1:8080' 并确保您的 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)                           
                    
                );

【讨论】:

以上是关于Angular 问题和“没有 'Access-Control-Allow-Origin' 标头” - 使用 OAuth 2、Passport、Express 和 Node的主要内容,如果未能解决你的问题,请参考以下文章

Angular 表单验证和引导样式

Angular2、NodeJS 和护照问题

Angular 2.0 和模态对话框

Angular 6 和业力'无法加载“@angular-devkit/build-angular”,它未注册'

部署 Web API 和 Angular

如何使用 angular5 和 angular 材质创建自定义颜色主题