我正在尝试为我的网络应用程序添加 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/