web-dev-qa-db-fra.com

Implémenter la connexion à l'API Facebook avec reactjs

Je travaille sur l'utilisation du SDK Javascript de Facebook pour l'authentification. J'ai été en mesure d'importer le SDK correctement et de mettre un bouton "J'aime" sur ma page. Mais, le bouton de connexion facebook doit être enveloppé dans la balise: 

<fb:login-button/>

J'ai actuellement tout le code du didacticiel de connexion Facebook collé dans mon index.html, le seul fichier html de mon projet, qui héberge l'application React. Mais, je dois mettre la dernière partie, qui contient le bouton de connexion, dans mon composant React. Quand j'ai essayé de faire cela, j'ai eu l'erreur suivante:

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.

Comment puis-je obtenir le bouton de connexion dans réagir?

35
ritmatter

J'ai compris comment modifier le didacticiel Facebook pour l'API de connexion avec ReactJS. J'espère que cela aide les autres personnes aux prises avec ce problème.

Tout d’abord, dans le composant react où vous voulez le lien de connexion, incluez ce code:

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

Ensuite, dans votre méthode de rendu, assurez-vous que vous avez du HTML qui appellera ce handleClick:

<a href="#" onClick={this.handleClick}>Login</a>

Notez que ceci est le même code du tutoriel, mais placé dans un composant ReactJS. La seule différence est que vous devez relier cela stratégiquement pour que les fonctions de l'API Facebook fassent partie intégrante de votre composant réag. Cette connexion se terminera par un message de réponse analysé à partir de la réponse donnée par FB.getLoginStatus (). Vous pouvez également extraire le jeton de cet objet de réponse et l'envoyer à votre serveur pour l'authentification avec quelque chose comme passport-facebook-token .

72
ritmatter

J'ai utilisé Promises pour Facebook Auth flow

mixins/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

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>
        );
    }
});
14
Zoreslav Goral

ritmatter a donné une bonne réponse, mais je vais montrer comment je l'ai fait un peu différemment. Je voulais utiliser le bouton de connexion de Facebook plutôt que le mien pour déclencher le rappel afin de vérifier l'état de la connexion. Le bouton de connexion peut ressembler à ceci:

<div class="fb-login-button" onlogin="checkLoginState" data-size="medium" data-show-faces="false" data-auto-logout-link="false"></div>

Le bouton a un attribut onlogin que l’analyseur jsx ne prend pas en charge. L'utilisation de data-onlogin de manière réactive ne fonctionnait pas, j'ai donc ajouté le bouton dans composantDidMount:

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

Il ne reste plus qu'à activer le bouton lors du montage du composant si vous souhaitez appeler automatiquement checkLoginState.

7
trad

J'affiche ici ma solution, car les réponses m'ont aidé à la mettre en œuvre, mais la réponse acceptée par ritmatter ne fonctionnait pas sans le

FB.Event.subscribe('auth.statusChange', function(response)

déclaration de la réponse de RubyFanatic ..__ De plus, le "onlogin" m'a beaucoup dérouté. Ce n'est tout simplement pas nécessaire à mes yeux.

Je veux le partager, car il s’agit d’une solution C & P, voici mon code complet contre fb api v2.8 (react-bootstrap peut être lancé bien sûr):

/* 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>
    );
  }
}
6
davey

C'est la solution que j'ai utilisée pour obtenir le rappel de connexion. Vous pouvez ajouter ce code pour votre bouton de connexion Facebook dans votre méthode render:

<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>

Dans votre code, ajoutez ces lignes:

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

L'appel de FB.Event.subscribe ('auth.statusChange', callback_function) lors de l'initialisation du composant est important car c'est essentiellement votre rappel de connexion. Commander ici pour FB.Event documentation.

3
RubyFanatic

J'ai écrit un cours de mixage pour résoudre ce problème.

https://github.com/genxstylez/react-oauth-mixin

1
genxstylez

C’est de loin le moyen le plus simple et le plus simple auquel je puisse penser si vous souhaitez utiliser le bouton de FB au lieu du vôtre.

Pour utiliser le bouton, c'est aussi simple que cela.

<FbLoginBtn
  width="250"
  dataScope="public_profile,email"
  onSuccess={callback}
  onFailure={optionalCallback}
  afterLogin={optionalCallback}
/>

Ce composant est complètement autonome et hautement compostable car il ne dépend d'aucune dépendance externe ni de comportement prédéfini autre que le rendu du bouton de connexion au 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;
0
Edmund Lee

Essayez d’utiliser cette bibliothèque: https://github.com/keppelen/react-facebook-login

Fonctionne assez simple:

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')
);
0
Vedmant

Je travaillais récemment sur Facebook Login pour l'un de mes projets. Ainsi, après avoir consulté de nombreuses réponses Stackoverflow et des articles de blog. J'ai écrit un code minimilastique en utilisant ES6 FatArrow Function Expression (à l'exclusion de .bind (this)). J'espère que ce code vous aide.

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;

0
Ronit Mukherjee

Trouvez le code le plus simple ci-dessous:

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;
0
Pankaj