我正在尝试为我的网络应用添加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));
}
}
答案 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的其他调用。