angular - 在 MEAN 应用程序中使用 passport-facebook 进行 facebook 登录时出现 CORS 错误

标签 angular express cors passport.js passport-facebook

我正在尝试为我的网络应用程序添加 facebook 登录功能。正在用 express js、mongodb 和 angular 2 开发。

应用程序的客户端部分是通过 angular-cli(在端口 4200 上运行)生成的。为了将它连接到 express 应用程序(在端口 4300 上运行),我使用了 angular-cli 本身提供的代理配置。

我已经在网上搜索过,但没有任何内容适合我。请帮帮我。

这是我在点击 facebook 登录按钮时遇到的错误

 XMLHttpRequest cannot load https://www.facebook.com/dialog/oauth?response_type=code&redirect_uri=http%…alhost%3A4200%2Fapi%2Fuser%2Ffacebook%2Fcallback&client_id=404659989876073. Redirect from 'https://www.facebook.com/dialog/oauth?response_type=code&redirect_uri=http%…alhost%3A4200%2Fapi%2Fuser%2Ffacebook%2Fcallback&client_id=404659989876073' to 'https://www.facebook.com/login.php?skip_api_login=1&api_key=404659989876073…_&display=page&locale=en_GB&logger_id=9f59d18b-00cb-48a9-a544-7e49a66acfe4' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access.

我可以理解这是 CORS 问题,我搜索了很多地方,但所有在线可用的解决方案都不适合我。比如在 express 中允许跨源,使用第三方库等。

这是我的app.ts

import * as express from 'express';
import { json, urlencoded } from 'body-parser';
import * as path from 'path';
import * as cors from 'cors';
import * as compression from 'compression';
import * as mongoose from 'mongoose';
import * as ejs from 'ejs';
import * as passport from 'passport';
import * as session from 'express-session';

import { MONGODB_URI } from './config';
import { AuthConfig } from './api/auth/passport';

import { thingRouter } from './api/thing/';
import { userRouter } from './api/user';

const app: express.Application = express();


app.disable('x-powered-by');

app.use(json());
app.use(compression());
app.use(urlencoded({ extended: true }));
app.use(session({ secret: 'my-secret-key', resave: true, saveUninitialized: true }));
app.use(passport.initialize());
app.use(passport.session());

mongoose.connect(process.env.MONGODB_URI || MONGODB_URI);

// allow cors only for local dev

app.use(cors({
  origin: 'http://localhost:4200'
}));


AuthConfig(passport);
// app.set('env', 'production');

// api routes

app.use('/api/thing', thingRouter);
app.use('/api/user', userRouter);

if (app.get('env') === 'production') {

  // in production mode run application from dist folder
  app.use(express.static(path.join(__dirname, '/../client')));
  app.engine('html', ejs.renderFile);
  app.set('view engin', 'html');
}

// catch 404 and forward to error handler
app.use(function (req: express.Request, res: express.Response, next) {
  res.render(path.join(__dirname, '/../client/index.html'));
});

// production error handler
// no stacktrace leaked to user
app.use(function (err: any, req: express.Request, res: express.Response, next: express.NextFunction) {

  res.status(err.status || 500);
  res.json({
    error: {},
    message: err.message
  });
});

export { app }

passport.ts

let LocalStrategy = require('passport-local').Strategy;
let FacebookStrategy = require('passport-facebook').Strategy;

import { FacebookAuth } from '../../config';

import { User } from '../user/user.model'

import * as uuid from 'uuid';

 let passportConfig = function (passport) {
  passport.serializeUser((user, done) => {
    console.log('serializeing user');
    done(null, user.id);
  });

  passport.deserializeUser((id, done) => {
    console.log('deserializing user');
    User.findOne({ id: id }, (err, user) => {
      done(err, user);
    })
  });


  // Facebook Strategy
  passport.use(new FacebookStrategy({
    clientID: FacebookAuth.clientId,
    clientSecret: FacebookAuth.clientSecret,
    callbackURL: FacebookAuth.callbackURL // for my app - 'http://localhost:4200/api/user/facebook/callback'
  },
  (token, refreshToken, profile, done) => {
    console.log('in passport.js'); //never printed
    console.log('token', token); //never printed
    console.log('refreshToken', refreshToken); //never printed
    console.log('profile', profile); // never printed
    User.findOne({ 'facebook.id': profile.id}, (err, user) => {
      if (err) { return done(err) }
      if (user) { return done(null, user) }
      let newUser = new User();
      newUser.id = uuid.v4();
      newUser.facebook.id = profile.id;
      newUser.facebook.token = token;
      newUser.name = profile.name.givenName + ' ' + profile.name.familyName;
      newUser.email = profile.emails[0].value;
      newUser.save(err => {
        if (err) { return done(err) }
        return done(null, newUser);
      })
    })
  }));
}

export let AuthConfig = passportConfig;

路由文件

import { Router } from 'express';

import { UserController } from './user.controller';

const userRouter: Router = Router();
const controller: UserController = new UserController();

userRouter.get('/facebook', controller.facebook);
userRouter.get('/facebook/callback', controller.facebookCallback);


export { userRouter };

用户 Controller 文件

import { Router, Response, Request, NextFunction } from 'express';
import * as passport from 'passport';
import * as uuid from 'uuid';

import { User } from './user.model';

export class UserController {
  constructor() { }

  facebook(req: Request, res: Response, next: NextFunction) {
    console.log('got the request in facebook()'); //this get printed
    passport.authenticate('facebook')(req, res, next);

  }

  facebookCallback(req: Request, res: Response, next: NextFunction) {
    console.log('got the call in facebookCallback()');
    passport.authenticate('facebook', (err, user) => {
      console.log('passport callback\'s callback');
      if (err) {
        return res.status(200)
        .json({
          title: 'error',
          data: err
        })
      }
      return res.status(200)
        .json({
          title: 'logged in',
          data: user
        })
    })
  }
}

** 带有点击事件的 facebook 图标的 HTML **

<div class="col-sm-2 col-sm-offset-4 fb" (click)="facebookLogin()">
        <i class="fa fa-facebook-square"></i>
 </div>

Angular 2 组件(函数)运行良好

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { ToastyService, ToastyConfig, ToastOptions, ToastData } from 'ng2-toasty';

import { AuthService } from './../../services/auth/auth.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.less']
})
export class LoginComponent implements OnInit {

  constructor(private toastyService: ToastyService,
    private router: Router,
    private toastyConfig: ToastyConfig,
    private authService: AuthService) {

    this.toastyConfig.theme = 'bootstrap';

  }

  ngOnInit() {
      }

  facebookLogin() {
    this.authService.facebookLogin()
    .subscribe(
      data => {
        console.log('login.component data', data);
      },
      err => {
        console.log('login.component err', err);
      }
    )
  }

}

授权服务

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs';
import 'rxjs/Rx';


@Injectable()
export class AuthService {

  constructor(private http: Http) {
  }

  facebookLogin() {
    return this.http.get('/api/user/facebook')
    .map(response => response.json())
    .catch(err => Observable.throw(err.json));
  }



}

最佳答案

这就是我为避免 Angular 将 facebook 身份验证对话 API 作为 AJAX 请求而调用的方法。

在您发送请求的Angular Controller Function中使用'window.location="http://localhost:3000/auth/facebook"';您的 Express Server,其中包含 passport.authenticate 内容。

它对我有用!

关于angular - 在 MEAN 应用程序中使用 passport-facebook 进行 facebook 登录时出现 CORS 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41450623/

相关文章:

node.js - Express 4.x 压缩

entity-framework - 问题包括查询中的导航属性

cors - 如何在 JAX-RS Web 服务上启用跨域请求?

angular - 为什么 Ngrx-Effects 不在继承的泛型类中自动订阅

javascript - 在heroku上运行 Angular 应用程序时出现应用程序错误

angular - 如何在 Angular Universal 中缓存破坏

ExpressJS 和 PassportJS 注销 - 后退按钮

javascript - nodeJS - Express 应提供引用的 main.js

javascript - Angular 2 中用于双向数据绑定(bind)的共享 RxJS 主题

javascript - 图像加载上的访问控制允许来源问题