Javascript 使用 reactjs 实现 Facebook API 登录
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27717555/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Implement Facebook API login with reactjs
提问by ritmatter
I'm working on using Facebook's Javascript SDK for authentication. I've been able to import the SDK properly and put a Like button on my page. But, the facebook login button has to be wrapped in the tag:
我正在使用 Facebook 的 Javascript SDK 进行身份验证。我已经能够正确导入 SDK 并在我的页面上放置一个 Like 按钮。但是,facebook 登录按钮必须包含在标签中:
<fb:login-button/>
I currently have all of the code from the Facebook Login tutorialpasted into my index.html, the only html file in my project, which houses the React application. But, I need to put the last part, which has the actual login button, into my React component. When I tried to do that, I got the following error:
我目前已将Facebook 登录教程中的所有代码粘贴到我的 index.html 中,这是我项目中唯一的 html 文件,其中包含 React 应用程序。但是,我需要将具有实际登录按钮的最后一部分放入我的 React 组件中。当我尝试这样做时,出现以下错误:
ReactifyError: /Users/ritmatter/reps/js/components/Signup.jsx: Parse Error: Line 82: Unexpected end of input while parsing file: /Users/ritmatter/reps/js/components/Signup.jsx
sdk.js:61 The "fb-root" div has not been created, auto-creating
ping?client_id=894010190618709&domain=localhost&origin=1&redirect_uri=http%3A%2F%2Fstatic.ak.facebo…:1 Given URL is not allowed by the Application configuration.: One or more of the given URLs is not allowed by the App's settings. It must match the Website URL or Canvas URL, or the domain must be a subdomain of one of the App's domains.
How can I get the login button into react?
我怎样才能让登录按钮做出反应?
回答by ritmatter
I have figured out how to modify the Facebook tutorial for the Login API with ReactJS. I hope this helps anyone else struggling with this.
我已经想出了如何使用 ReactJS 修改登录 API 的 Facebook 教程。我希望这可以帮助其他任何为此苦苦挣扎的人。
Firstly, in the react component where you want the Login link, include this code:
首先,在需要登录链接的 react 组件中,包含以下代码:
componentDidMount: function() {
window.fbAsyncInit = function() {
FB.init({
appId : '<YOUR_APP_ID>',
cookie : true, // enable cookies to allow the server to access
// the session
xfbml : true, // parse social plugins on this page
version : 'v2.1' // use version 2.1
});
// Now that we've initialized the JavaScript SDK, we call
// FB.getLoginStatus(). This function gets the state of the
// person visiting this page and can return one of three states to
// the callback you provide. They can be:
//
// 1. Logged into your app ('connected')
// 2. Logged into Facebook, but not your app ('not_authorized')
// 3. Not logged into Facebook and can't tell if they are logged into
// your app or not.
//
// These three cases are handled in the callback function.
FB.getLoginStatus(function(response) {
this.statusChangeCallback(response);
}.bind(this));
}.bind(this);
// Load the SDK asynchronously
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
},
// Here we run a very simple test of the Graph API after login is
// successful. See statusChangeCallback() for when this call is made.
testAPI: function() {
console.log('Welcome! Fetching your information.... ');
FB.api('/me', function(response) {
console.log('Successful login for: ' + response.name);
document.getElementById('status').innerHTML =
'Thanks for logging in, ' + response.name + '!';
});
},
// This is called with the results from from FB.getLoginStatus().
statusChangeCallback: function(response) {
console.log('statusChangeCallback');
console.log(response);
// The response object is returned with a status field that lets the
// app know the current login status of the person.
// Full docs on the response object can be found in the documentation
// for FB.getLoginStatus().
if (response.status === 'connected') {
// Logged into your app and Facebook.
this.testAPI();
} else if (response.status === 'not_authorized') {
// The person is logged into Facebook, but not your app.
document.getElementById('status').innerHTML = 'Please log ' +
'into this app.';
} else {
// The person is not logged into Facebook, so we're not sure if
// they are logged into this app or not.
document.getElementById('status').innerHTML = 'Please log ' +
'into Facebook.';
}
},
// This function is called when someone finishes with the Login
// Button. See the onlogin handler attached to it in the sample
// code below.
checkLoginState: function() {
FB.getLoginStatus(function(response) {
this.statusChangeCallback(response);
}.bind(this));
},
handleClick: function() {
FB.login(this.checkLoginState());
},
Then, in your render method, make sure you have some HTML that will call that handleClick:
然后,在您的渲染方法中,确保您有一些 HTML 会调用该 handleClick:
<a href="#" onClick={this.handleClick}>Login</a>
Note, this is the same code from the tutorial, but placed in a ReactJS component. The only difference is that you have to bind this strategically to make the Facebook API functions part of your react component. This login will finish with a response message parsed from the response given by FB.getLoginStatus(). You can also take the token out of that response object and send it to your backend for authentication with something like passport-facebook-token.
请注意,这与教程中的代码相同,但放置在 ReactJS 组件中。唯一的区别是你必须战略性地绑定它,使 Facebook API 函数成为你的 React 组件的一部分。此登录将以从 FB.getLoginStatus() 给出的响应中解析出的响应消息结束。您还可以从该响应对象中取出令牌,并将其发送到您的后端以使用诸如Passport-facebook-token 之类的东西进行身份验证。
回答by Zoreslav Goral
I used Promises for Facebook Auth flow
我在 Facebook Auth 流程中使用了 Promises
mixins/facebook.js
混合/facebook.js
const promises = {
init: () => {
return new Promise((resolve, reject) => {
if (typeof FB !== 'undefined') {
resolve();
} else {
window.fbAsyncInit = () => {
FB.init({
appId : '<app_id>',
cookie : true,
xfbml : true,
version : 'v2.5'
});
resolve();
};
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
}
});
},
checkLoginState: () => {
return new Promise((resolve, reject) => {
FB.getLoginStatus((response) => {
response.status === 'connected' ? resolve(response) : reject(response);
});
});
},
login: () => {
return new Promise((resolve, reject) => {
FB.login((response) => {
response.status === 'connected' ? resolve(response) : reject(response);
});
});
},
logout: () => {
return new Promise((resolve, reject) => {
FB.logout((response) => {
response.authResponse ? resolve(response) : reject(response);
});
});
},
fetch: () => {
return new Promise((resolve, reject) => {
FB.api(
'/me',
{fields: 'first_name, last_name, gender'},
response => response.error ? reject(response) : resolve(response)
);
});
}
}
export const Facebook = {
doLogin() {
this.setState({
loading: true
}, () => {
promises.init()
.then(
promises.checkLoginState,
error => { throw error; }
)
.then(
response => { this.setState({status: response.status}); },
promises.login
)
.then(
promises.fetch,
error => { throw error; }
)
.then(
response => { this.setState({loading: false, data: response, status: 'connected'}); },
error => { throw error; }
)
.catch((error) => {
this.setState({loading: false, data: {}, status: 'unknown'});
console.warn(error);
});
});
},
doLogout() {
this.setState({
loading: true
}, () => {
promises.init()
.then(
promises.checkLoginState,
error => { throw error; }
)
.then(
promises.logout,
error => { this.setState({data: {}, status: 'unknown'}); }
)
.then(
response => { this.setState({loading: false, data: {}, status: 'unknown'}); },
error => { throw error; }
)
.catch(error => {
this.setState({loading: false, data: {}, status: 'unknown'});
console.warn(error);
});
});
},
checkStatus() {
this.setState({
loading: true
}, () => {
promises.init()
.then(
promises.checkLoginState,
error => { throw error; }
)
.then(
response => { this.setState({status: response.status}); },
error => { throw error; }
)
.then(
promises.fetchUser,
error => { throw error; }
)
.then(
response => { this.setState({loading: false, data: response, status: 'connected'}); },
error => { throw error; }
)
.catch((error) => {
this.setState({loading: false, data: {}, status: 'unknown'});
console.warn(error);
});
});
}
};
Profile.jsx
配置文件.jsx
import {Facebook} from './mixins/Facebook.js';
import {Button} from 'react-bootstrap';
const ProfileHandler = React.createClass({
mixins: [Facebook],
componentDidMount() {
this.checkStatus();
},
getInitialState() {
return {
status: 'unknown',
loading: false,
data: {}
};
},
render() {
const loading = this.state.loading ? <p>Please wait, profile is loading ...</p> : null;
const message = this.state.status === 'connected'
? (<div>
Hi {data.name}!
<Button onClick={this.doLogout}>Logout</Button>
</div>)
: (<Button onClick={this.doLogin}>Login</Button>);
return (
<div>
{message}
{loading}
</div>
);
}
});
回答by davey
I post my solution here, as the answers helped me to implement it, but the accepted answer from ritmatter did not work without the
我在这里发布了我的解决方案,因为答案帮助我实现了它,但是 ritmatter 接受的答案没有
FB.Event.subscribe('auth.statusChange', function(response)
statement from RubyFanatic's answer. Furthermore the "onlogin" confused me a lot. It is simply not required in my eyes.
来自 RubyFanatic 的回答的声明。此外,“登录”让我很困惑。在我看来,它根本不需要。
I want to share it, as this is a c&p solution, here my full code against fb api v2.8 (react-bootstrap can be kicked of course):
我想分享它,因为这是一个c&p解决方案,这里是我针对fb api v2.8的完整代码(当然可以踢react-bootstrap):
/* global FB*/
import React, { Component } from 'react';
import { Grid, Row, Col } from 'react-bootstrap';
export default class Login extends Component {
constructor(props) {
super(props);
this.checkLoginState = this.checkLoginState.bind(this);
this.handleClick = this.handleClick.bind(this);
this.testAPI = this.testAPI.bind(this);
this.statusChangeCallback = this.statusChangeCallback.bind(this);
}
componentDidMount() {
window.fbAsyncInit = function() {
FB.init({
appId : 'YOURAPIKEYHERE',
cookie : true,
xfbml : true,
version : 'v2.8'
});
FB.AppEvents.logPageView();
FB.Event.subscribe('auth.statusChange', function(response) {
if (response.authResponse) {
this.checkLoginState();
} else {
console.log('---->User cancelled login or did not fully authorize.');
}
}.bind(this));
}.bind(this);
// Load the SDK asynchronously
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = '//connect.facebook.net/en_US/sdk.js';
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
}
// Here we run a very simple test of the Graph API after login is
// successful. See statusChangeCallback() for when this call is made.
testAPI() {
console.log('Welcome! Fetching your information.... ');
FB.api('/me', function(response) {
console.log('Successful login for: ' + response.name);
document.getElementById('status').innerHTML =
'Thanks for logging in, ' + response.name + '!';
});
}
// This is called with the results from from FB.getLoginStatus().
statusChangeCallback(response) {
if (response.status === 'connected') {
// Logged into your app and Facebook.
this.testAPI();
} else if (response.status === 'not_authorized') {
// The person is logged into Facebook, but not your app.
document.getElementById('status').innerHTML = 'Please log ' +
'into this app.';
} else {
// The person is not logged into Facebook, so we're not sure if
// they are logged into this app or not.
document.getElementById('status').innerHTML = 'Please log ' +
'into Facebook.';
}
}
checkLoginState() {
FB.getLoginStatus(function(response) {
this.statusChangeCallback(response);
}.bind(this));
}
handleClick() {
FB.login(this.checkLoginState());
}
render() {
return (
<main>
<Grid fluid>
<h1>
Facebook Login
</h1>
</Grid>
<Grid>
<Row>
<Col xs={12}>
<a href="#" onClick={this.handleClick} onlogin={this.checkLoginState}>Login</a>
<div id="status"></div>
</Col>
</Row>
</Grid>
</main>
);
}
}
回答by trad
ritmatter gave a good answer, but I'll show how I did this a little differently. I wanted to use Facebook's login button rather than my own to trigger the callback for checking login state. The login button might look like this:
ritmatter 给出了一个很好的答案,但我将展示我是如何做到这一点的。我想使用 Facebook 的登录按钮而不是我自己的按钮来触发检查登录状态的回调。登录按钮可能如下所示:
<div class="fb-login-button" onlogin="checkLoginState" data-size="medium" data-show-faces="false" data-auto-logout-link="false"></div>
The button has an onlogin attribute, which the jsx parser doesn't support. Using data-onlogin in the react fashion wasn't working, so I just added the button in componentDidMount:
该按钮有一个 onlogin 属性,jsx 解析器不支持该属性。以反应方式使用 data-onlogin 不起作用,所以我只是在 componentDidMount 中添加了按钮:
componentWillMount: function () {
window['statusChangeCallback'] = this.statusChangeCallback;
window['checkLoginState'] = this.checkLoginState;
},
componentDidMount: function () {
var s = '<div class="fb-login-button" ' +
'data-scope="public_profile,email" data-size="large" ' +
'data-show-faces="false" data-auto-logout-link="true" ' +
'onlogin="checkLoginState"></div>';
var div = document.getElementById('social-login-button-facebook')
div.innerHTML = s;
},
componentWillUnmount: function () {
delete window['statusChangeCallback'];
delete window['checkLoginState'];
},
statusChangeCallback: function(response) {
console.log(response);
},
// Callback for Facebook login button
checkLoginState: function() {
console.log('checking login state...');
FB.getLoginStatus(function(response) {
statusChangeCallback(response);
});
},
render: function() {
return (
<div id='social-login-button-facebook'>
</div>
);
}
All that's left to do is trigger the button upon mounting the component if you want to automatically call checkLoginState.
如果您想自动调用 checkLoginState,剩下要做的就是在安装组件时触发按钮。
回答by RubyFanatic
This is the solution I used to get login callback. You can add this code for your Facebook login button in your rendermethod:
这是我用来获取登录回调的解决方案。您可以在渲染方法中为 Facebook 登录按钮添加此代码:
<div className="fb-login-button" data-max-row="5"
data-size="large"
data-show-faces="false"
data-auto-logout-link="false"
href="javascript:void(0)">Login</div>
In your code, add these lines:
在您的代码中,添加以下几行:
componentDidMount: function() {
// facebook signin button render
window.fbAsyncInit = function() {
FB.init({
appId : 'replace with your app id here',
cookie : true, // enable cookies to allow the server to access
// the session
xfbml : true, // parse social plugins on this page
version : 'v2.1' // use version 2.1
});
// login callback implementation goes inside the function() { ... } block
FB.Event.subscribe('auth.statusChange', function(response) {
// example implementation
if (response.authResponse) {
console.log('Welcome! Fetching your information.... ');
FB.api('/me', function(response) {
console.log('Good to see you, ' + response.name + '.');
});
} else {
console.log('User cancelled login or did not fully authorize.');
}
});
}.bind(this);
// Load the SDK asynchronously
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
}
}
Calling FB.Event.subscribe('auth.statusChange', callback_function)during component initialization is important because that's basically your login callback. Checkout here for FB.Eventdocumentation.
在组件初始化期间调用FB.Event.subscribe('auth.statusChange', callback_function)很重要,因为这基本上是您的登录回调。在此处查看FB.Event文档。
回答by Ronit Mukherjee
I was recently working on Facebook Loginfor one of my project, So after going though many Stackoverflow answers and blog posts. I wrote a minimilastic code using ES6 FatArrow Function Expression (excluding .bind(this)). Hope this code helps you.
我最近为我的一个项目在Facebook 登录上工作,所以在浏览了许多 Stackoverflow 答案和博客文章之后。我使用 ES6 FatArrow 函数表达式(不包括 .bind(this))编写了一个 minimilastic 代码。希望此代码对您有所帮助。
https://gist.github.com/ronit-mukherjee/3e933509643a4ab4e80452bb05c1a073
https://gist.github.com/ronit-mukherjee/3e933509643a4ab4e80452bb05c1a073
/*global FB*/
import React, {
Component
} from 'react';
class FacebookLoginButton extends Component {
componentDidMount() {
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {
return;
}
js = d.createElement(s);
js.id = id;
js.src = "https://connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
window.fbAsyncInit = () => {
FB.init({
appId: '9999999999999999', //Change with your Facebook app id
autoLogAppEvents: true,
xfbml: true,
version: 'v3.0'
});
FB.Event.subscribe('auth.statusChange', response => {
if (response.authResponse) {
this.checkLoginState();
} else {
console.log('[FacebookLoginButton] User cancelled login or did not fully authorize.');
}
});
};
}
checkLoginState() {
FB.getLoginStatus(function(response) {
this.statusChangeCallback(response);
}.bind(this));
}
login() {
FB.login(this.checkLoginState(), {
scope: 'email'
});
}
statusChangeCallback(response) {
if (response.status === 'connected') {
this.testAPI();
} else if (response.status === 'not_authorized') {
console.log("[FacebookLoginButton] Person is logged into Facebook but not your app");
} else {
console.log("[FacebookLoginButton] Person is not logged into Facebook");
}
}
testAPI() {
FB.api('/me', function(response) {
console.log('[FacebookLoginButton] Successful login for: ', response);
});
}
render() {
return ( <
button className = "btn btn-block btn-fb"
onClick = {
() => this.login()
} >
<
i className = "fa fa-facebook" / > Connect with Facebook <
/button>
)
}
}
export default FacebookLoginButton;
回答by genxstylez
I wrote a mixin class to address this.
我写了一个 mixin 类来解决这个问题。
回答by Vedmant
Try using this library: https://github.com/keppelen/react-facebook-login
尝试使用这个库:https: //github.com/keppelen/react-facebook-login
Works quite straightforward:
工作非常简单:
import React from 'react';
import ReactDOM from 'react-dom';
import FacebookLogin from 'react-facebook-login';
const responseFacebook = (response) => {
console.log(response);
}
ReactDOM.render(
<FacebookLogin
appId="1088597931155576"
autoLoad={true}
callback={responseFacebook} />,
document.getElementById('demo')
);
回答by Pankaj
Find simplest code below:
在下面找到最简单的代码:
import React, { Component } from 'react';
import './App.css';
import FacebookLogin from 'react-facebook-login';
import GoogleLogin from 'react-google-login';
class App extends Component {
render() {
const responseFacebook = (response) => {
console.log(response);
}
const responseGoogle = (response) => {
console.log(response);
}
return (
<div className="App">
<h1>LOGIN WITH FACEBOOK AND GOOGLE</h1>
<FacebookLogin
appId="" //APP ID NOT CREATED YET
fields="name,email,picture"
callback={responseFacebook}
/>
<br />
<br />
<GoogleLogin
clientId="" //CLIENTID NOT CREATED YET
buttonText="LOGIN WITH GOOGLE"
onSuccess={responseGoogle}
onFailure={responseGoogle}
/>
</div>
);
}
}
export default App;
回答by Edmund Lee
This is by far the cleanest and simplest way I could think of if you want to use the button from FB instead of your own.
如果您想使用来自 FB 的按钮而不是您自己的按钮,这是迄今为止我能想到的最简洁、最简单的方法。
To use the button, it's as simple as this.
要使用按钮,就这么简单。
<FbLoginBtn
width="250"
dataScope="public_profile,email"
onSuccess={callback}
onFailure={optionalCallback}
afterLogin={optionalCallback}
/>
This component is completely self-contained, and highly compostable because it doesn't rely on any external dependency nor does it have any predefined behavior other than rendering the FB login button.
这个组件是完全独立的,并且高度可堆肥,因为它不依赖任何外部依赖,也没有任何预定义的行为,除了呈现 FB 登录按钮。
import React, { Component } from 'react';
class FbLoginBtn extends Component {
constructor(props) {
super(props);
// post login behavior should be defined at a higher level
this.onSuccess = this.props.onSuccess || (() => {});
this.onFailure = this.props.onFailure || (() => {});
this.onSuccess = this.onSuccess.bind(this);
this.onFailure = this.onFailure.bind(this);
}
componentDidMount() {
// This is the meat of the component
// create a script tag, load FB SDK
// then after script is loaded, set related behavior
// If you have other components that rely on the FB SDK
// I recommend extracting this into its own module
let self = this;
let scriptTag = document.createElement('script');
scriptTag.type = 'text/javascript';
scriptTag.src = "http://connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.4&appId=xxxxx";
scriptTag.addEventListener('load', function (e) {
self.FB = window.FB;
// I don't like exposing the SDK to global scope
window.FB = null;
// This subscribe the callback when login status change
// Full list of events is here
// https://developers.facebook.com/docs/reference/javascript/FB.Event.subscribe/v2.9
self.FB.Event.subscribe('auth.statusChange', self.onStatusChange.bind(self));
});
document.body.appendChild(scriptTag);
}
onStatusChange(response) {
if (response.status === 'connected') {
const { accessToken } = response.authResponse;
// I have a afterLogin optional callback
// which takes care of ads landing, invitation or any other custom behavior
this.onSuccess(accessToken, this.props.afterLogin);
} else {
this.onFailure();
}
}
render() {
return (
<div
className="fb-login-button"
data-width={this.props.width}
data-max-rows="1"
data-size="large"
data-button-type="login_with"
data-show-faces="false"
data-auto-logout-link="true"
data-use-continue-as="false"
data-scope={this.props.dataScope}
>
</div>
);
}
}
export default FbLoginBtn;

