2013-12-10 10 views
10

Sto lavorando a una funzione che consente agli utenti di accedere al mio sito Web con il proprio account Google.Accesso a Google+ con il problema di callback JavaScript

Il mio codice è basato su Google documentation (le altre opzioni signIn() sono nei metatag).

function login() { 
    gapi.auth.signIn({'callback': 
    function (authResult) { 
     if (authResult['status']['signed_in']) { 
     console.log('Okay'); 
     }else { 
     console.log('Error'); 
     } 
    } 
    }); 
} 

Quando chiamo login(), un pop-up di Google appare, approvo i termini della mia applicazione e tutto funziona bene.

Ma il callback viene chiamato due volte:

  • 1 ° caso: Se non ho mai approvato apps permessi allora il callback sarà chiamata in apertura del pop-up e quando sarò approvare le autorizzazioni. Quindi scriverà "Errore" e "Ok".
  • Secondo caso: se ho già approvato i permessi, scriverò "Ok" due volte.

Ho aggiunto l'opzione 'approvalprompt': 'force' alla funzione signIn(). La funzione di callback non viene più chiamata due volte, ma costringe l'utente ad approvare le autorizzazioni dell'app, anche se precedentemente approvate. Quindi non è facile da usare.

Esiste un modo amichevole per approvare le autorizzazioni dell'app una sola volta senza due richiamate?

Grazie.

+0

possibile duplicato di [Google Login Hitting Twice?] (Http://stackoverflow.com/questions/23020733/google-login-hitting-twice) –

+0

Sembra che questo sia un problema comune. C'è una risposta qui: stackoverflow.com/questions/23020733/... - –

risposta

4

tenta di registrare prima chiamata in qualche variabile locale e poi elaborarlo

questa soluzione veloce mi aiuta:

function login() { 
    var initializedGoogleCallback = false 
    gapi.auth.signIn({ 
    'callback': function (authResult) { 
     if (!initializedGoogleCallback) { 
     // after first call other will be ignored 
     initializedGoogleCallback = true; 
     if (authResult['status']['signed_in']) { 
      console.log('Okay'); 
     } else { 
      console.log('Error'); 
     } 
     } 
    } 
    }); 
} 

inoltre è possibile aggiungere seguente codice prima chiamare gapi.auth.signIn

window.removeEventListener('load') 
+0

È una buona soluzione grazie! Ma ancora non so perché dobbiamo farlo, è come "barare". Forse è un bug o semplicemente non capiamo il motivo. – sylvhama

+1

Penso che il motivo sia nella libreria di google js. Ma Google non fornisce il modo normale per rimuovere tutti gli eventi precedenti prima della nuova chiamata di metodo. Inoltre non esiste una fonte js per comprendere appieno la ragione e l'API non lo descrive. – Panoptik

6

Sono di fronte allo stesso problema: callin di callin chiamato due volte in caso di utente che ha già concesso l'autorizzazione; l'approccio alla variabile locale (initializedGoogleCallback) non funziona per me perché chiama la richiamata una sola volta solo quando l'utente ha già concesso l'accesso, ma non lo ha chiamato se l'utente è il nuovo. Dopo un po 'di ricerche (in particolare ho scavato nel sito usando g + auth) ho notato che tutti usano lo 'approvalprompt': 'force' e hanno l'utente già autorizzato a ripetere ogni volta un criterio di "accesso non in linea". Anche l'esempio di google che ho seguito per configurare la mia app (https://developers.google.com/+/web/signin/javascript-flow) anche se non lo menzionava, utilizza il parametro "force". Per il momento sembra l'unica soluzione se si desidera utilizzare il flusso javascript (che significa se è necessario un pulsante di accesso stile personale)

1

Questo è il piano intenzionale per la configurazione a livello di pagina! Essendo presente nella pagina, il callback si attiva quando viene completato il caricamento di Javascript. Quello che dovresti fare è prepararti per quello nel tuo codice.

Non mostrare il pulsante di accesso finché non si riceve una richiamata - se authResult['status']['signed_in'] == true, quindi trattare l'utente come eseguito l'accesso (impostare una sessione, ecc., Qualunque cosa si farebbe normalmente). Se è falso, quindi visualizza il pulsante.

Eviterei di usare l'approvazione prompt force se potete!

+0

Come nascondere un pulsante di aiuto se l'utente deve cliccarlo per attivare la richiamata? Nascondere un pulsante non risolve un doppio problema di callback. – CRONUS

+0

Per il metodo javascript, non è necessario fare clic su di esso per attivare una richiamata: verrà attivata non appena viene aggiunta al DOM. Se si utilizza la configurazione a livello di pagina, verrà attivato non appena il caricamento della pagina sarà completato. Quindi il flusso sarebbe: caricamento della pagina, richiamato dal callback, se non firmato nel pulsante di visualizzazione. –

+0

Forse non capisco qualcosa lì - [JS workflow] (http://developers.google.com/+/web/signin/javascript-flow). Quote: _Si dovrebbero utilizzare solo eventi avviati dall'utente per attivare questo metodo, come i clic, in modo che i blocchi popup non impediscano l'apertura della finestra di dialogo dell'autorizzazione. Anche nell'esempio _onload_ chiama semplicemente 'render()', che aggiunge eventListener al pulsante. La richiamata non viene richiamata durante il caricamento della pagina. – CRONUS

0

infine ho risolto con una soluzione; non so se questo è il modo corretto di avvicinarsi o io sono solo barare, ma lo faccio in questo modo:

prima di tutto un po 'di script nella pagina (sto usando bootstrap + jquery)

function render() { 
    //I am not using it but kept anyway 

} 
var i; 
// Function called from a onClick on a link or button (the 'sign in with g+' button) 
function gp_login() { 
    i=0; 
    $('#alertbox').remove(); 
    var additionalParams = { 
    'callback': signinCallback, 
    /*'approvalprompt': 'force' finally removed*/ 
    }; 
    $('#gp-login').button('loading'); 
    gapi.auth.signIn(additionalParams); 
} 

function signinCallback(authResult) { //my callback function 
     var email=''; 
     var given_name=''; 
     if (authResult['status']['signed_in']) { //get some user info 
      gapi.client.load('oauth2', 'v2', function() { 
       gapi.client.oauth2.userinfo.get().execute(function(resp){ 
        email = resp.email; //get user email 
        given_name = resp.given_name; //get user email 
        family_name=resp.family_name; 
        id=resp.id; 
        if (i<2) { //execute the doLogin just one time (my cheat) 
         doLogin(email,given_name,family_name,id); //dologin does my logic with an ajax call to signup/register user to my site 
        } 
        i=2; 
       }); 
      }); 
     } else { 
     // Update the app to reflect a signed out user 
     } 

} 

questo approcio ha la parte doLogin chiamata solo una volta, ma il callback è chiamato due volte (gapi.client.oauth2.userinfo.get() questa funzione viene chiamata due volte); con un po 'più di tweaking con il controllo if/var penso sia possibile chiamare tutto una volta. In questo modo se l'utente ha già concesso l'autenticazione, verrà automaticamente firmato.

Ho notato che a volte Google ha uno strato di pop-up sul fondo dello strato che mostra un "messaggio di benvenuto di nuovo", ma non ho capito quando appare o se devo chiamare manualmente

+0

Ho a che fare con lo stesso problema e ho finito per implementare una 'correzione' simile ma con una variabile vero/falso. – Francisc0

8

Sono affrontare questo stesso problema qui, ma sto chiamando gapi.auth.signIn() tramite un gestore di clic del pulsante. Il callback è ancora chiamato due volte. Una cosa che ho notato tra i due oggetti authResult era che authResult.status.method è 'AUTO' nella prima chiamata (prima che appaia la finestra popup) ed è 'PROMPT' nella seconda chiamata dopo che la finestra è stata chiusa automaticamente a causa della precedente autorizzazione.

La soluzione che sto esplorando ora è di ignorare l'istanza AUTO e processare solo l'istanza PROMPT del callback. Non so come funzionerà una volta che revocherò le autorizzazioni all'interno di Google a causa della mancanza di dettagli nei documenti sull'oggetto 'stato'.

+0

Come ha funzionato questo per te? Sto pensando di fare lo stesso. – Dale

1

Come risposta del Drew Taylor, per evitare il doppio di richiamata con il segno javascript puro in soluzione, è possibile check the user's session state:

if (authResult["status"]["method"] == "PROMPT") {...} 

Penso che la richiamata con il metodo AUTO viene licenziato dalla barra di benvenuto in basso che appare al primo accesso.