在MEAN app中使用passport-facebook登录facebook时出现CORS错误

时间:2017-01-03 19:05:42

标签: angular express cors passport.js passport-facebook

我正在尝试为我的网络应用添加Facebook登录功能。正在快递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问题,我搜索了很多地方但是在线提供的所有解决方案都不适用于我。就像在快递中允许交叉起源一样,使用第三方库等等。

这是我的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 };

用户控制器文件

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 for facebook图标

<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));
  }



}

3 个答案:

答案 0 :(得分:1)

尝试使用http://localhost:port/api/users/facebook之类的链接 并设置标题 导入标题和集 header.append(&#39; Conent型&#39;&#39;应用/ JSON&#39);

答案 1 :(得分:1)

这就是我所做的,以避免Angular将facebook auth对话API称为AJAX请求。

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

对我有用!

答案 2 :(得分:1)

我有完全相同的问题。 我尝试以类似的方式解决它 amey ,但它以express创建两个不同的会话结束:一个用于authed客户端,另一个用于来自frontside app的其他调用。