tutorial español javascript typescript angular google-login

javascript - español - Inicio de sesión en Google para sitios web y Angular 2 usando Typescript



nativescript angular (4)

Estoy construyendo un sitio que tiene un servicio web RESTful bastante estándar para manejar la persistencia y la lógica empresarial compleja. La interfaz de usuario que estoy creando para consumir este servicio utiliza Angular 2 con componentes escritos en TypeScript.

En lugar de crear mi propio sistema de autenticación, espero confiar en el inicio de sesión de Google para sitios web. La idea es que los usuarios accedan al sitio, inicien sesión a través del marco provisto allí y luego envíen los tokens de ID resultantes, que el servidor que aloja el servicio RESTful puede verificar.

En la documentación de inicio de sesión de Google hay instrucciones para crear el botón de inicio de sesión a través de JavaScript, que es lo que debe suceder ya que el botón de inicio de sesión se representa dinámicamente en una plantilla angular. La parte relevante de la plantilla:

<div class="login-wrapper"> <p>You need to log in.</p> <div id="{{googleLoginButtonId}}"></div> </div> <div class="main-application"> <p>Hello, {{userDisplayName}}!</p> </div>

Y la definición del componente Angular 2 en Typescript:

import {Component} from "angular2/core"; // Google''s login API namespace declare var gapi:any; @Component({ selector: "sous-app", templateUrl: "templates/sous-app-template.html" }) export class SousAppComponent { googleLoginButtonId = "google-login-button"; userAuthToken = null; userDisplayName = "empty"; constructor() { console.log(this); } // Angular hook that allows for interaction with elements inserted by the // rendering of a view. ngAfterViewInit() { // Converts the Google login button stub to an actual button. api.signin2.render( this.googleLoginButtonId, { "onSuccess": this.onGoogleLoginSuccess, "scope": "profile", "theme": "dark" }); } // Triggered after a user successfully logs in using the Google external // login provider. onGoogleLoginSuccess(loggedInUser) { this.userAuthToken = loggedInUser.getAuthResponse().id_token; this.userDisplayName = loggedInUser.getBasicProfile().getName(); console.log(this); } }

El flujo básico va:

  1. Angular representa la plantilla y el mensaje "¡Hola, vacío!" se muestra.
  2. El gancho ngAfterViewInit se ngAfterViewInit y se llama al método gapi.signin2.render(...) , que convierte el div vacío en un botón de inicio de sesión de Google. Esto funciona correctamente y al hacer clic en ese botón se activará el proceso de inicio de sesión.
  3. Esto también onGoogleLoginSuccess método onGoogleLoginSuccess del componente para procesar realmente el token devuelto después de que un usuario inicia sesión.
  4. Angular detecta que la propiedad userDisplayName ha cambiado y actualiza la página para mostrar ahora "¡Hola, Craig (o como se userDisplayName )!".

El primer problema que ocurre es en el método onGoogleLoginSuccess . Observe que console.log(...) llama al constructor y a ese método. Como se esperaba, el que está en el constructor devuelve el componente angular. El que está en el método onGoogleLoginSuccess , sin embargo, devuelve el objeto de la window JavaScript.

Parece que el contexto se está perdiendo en el proceso de saltar a la lógica de inicio de sesión de Google, así que mi próximo paso fue intentar incorporar la llamada $.proxy jQuery para $.proxy al contexto correcto. Así que importo el espacio de nombres jQuery agregando declare var $:any; en la parte superior del componente y luego convierta el contenido del método ngAfterViewInit en:

// Angular hook that allows for interaction with elements inserted by the // rendering of a view. ngAfterViewInit() { var loginProxy = $.proxy(this.onGoogleLoginSuccess, this); // Converts the Google login button stub to an actual button. gapi.signin2.render( this.googleLoginButtonId, { "onSuccess": loginProxy, "scope": "profile", "theme": "dark" }); }

Después de agregar eso, las dos llamadas a console.log devuelven el mismo objeto, por lo que los valores de propiedad ahora se actualizan correctamente. El segundo mensaje de registro muestra el objeto con los valores de propiedad actualizados esperados.

Lamentablemente, la plantilla angular no se actualiza cuando sucede esto. Mientras estaba depurando, tropecé con algo que creo que explica lo que está sucediendo. ngAfterViewInit la siguiente línea al final del ngAfterViewInit :

setTimeout(function() { this.googleLoginButtonId = this.googleLoginButtonId }, 5000);

Esto no debería hacer nada. Solo espera cinco segundos después de que el gancho finaliza y luego establece un valor de propiedad igual a él. Sin embargo, con la línea en su lugar, "Hello, empty!" el mensaje se convierte en "Hello, Craig!" unos cinco segundos después de que la página se haya cargado. Esto me sugiere que Angular simplemente no está notando que los valores de las propiedades están cambiando en el método onGoogleLoginSuccess . Entonces, cuando sucede algo más que notifica a Angular que los valores de las propiedades han cambiado (como la autoasignación inútil anterior), Angular se despierta y actualiza todo.

Obviamente, eso no es un truco que quiero dejar en el lugar, así que me pregunto si algún experto en Angular puede darme alguna pista. ¿Hay alguna llamada que deba hacer para obligar a Angular a notar que algunas propiedades han cambiado?

ACTUALIZADO el 21-02-2016 para brindar claridad sobre la respuesta específica que resolvió el problema

Terminé necesitando usar ambas piezas de la sugerencia proporcionada en la respuesta seleccionada.

Primero, exactamente como se sugirió, necesitaba convertir el método onGoogleLoginSuccess para usar una función de flecha. En segundo lugar, necesitaba hacer uso de un objeto NgZone para asegurarme de que las actualizaciones de propiedad ocurrieran en un contexto que Angular conoce. Entonces el método final terminó luciendo como

onGoogleLoginSuccess = (loggedInUser) => { this._zone.run(() => { this.userAuthToken = loggedInUser.getAuthResponse().id_token; this.userDisplayName = loggedInUser.getBasicProfile().getName(); }); }

_zone importar el objeto _zone : import {Component, NgZone} from "angular2/core";

También necesitaba inyectarlo como se sugiere en la respuesta a través del contructor de la clase: constructor(private _zone: NgZone) { }


Hice un componente de inicio de sesión de google si quieres un ejemplo.

ngOnInit() { this.initAPI = new Promise( (resolve) => { window[''onLoadGoogleAPI''] = () => { resolve(window.gapi); }; this.init(); } ) } init(){ let meta = document.createElement(''meta''); meta.name = ''google-signin-client_id''; meta.content = ''xxxxx-xxxxxx.apps.googleusercontent.com''; document.getElementsByTagName(''head'')[0].appendChild(meta); let node = document.createElement(''script''); node.src = ''https://apis.google.com/js/platform.js?onload=onLoadGoogleAPI''; node.type = ''text/javascript''; document.getElementsByTagName(''body'')[0].appendChild(node); } ngAfterViewInit() { this.initAPI.then( (gapi) => { gapi.load(''auth2'', () => { var auth2 = gapi.auth2.init({ client_id: ''xxxxx-xxxxxx.apps.googleusercontent.com'', cookiepolicy: ''single_host_origin'', scope: ''profile email'' }); auth2.attachClickHandler(document.getElementById(''googleSignInButton''), {}, this.onSuccess, this.onFailure ); }); } ) } onSuccess = (user) => { this._ngZone.run( () => { if(user.getAuthResponse().scope ) { //Store the token in the db this.socialService.googleLogIn(user.getAuthResponse().id_token) } else { this.loadingService.displayLoadingSpinner(false); } } ); }; onFailure = (error) => { this.loadingService.displayLoadingSpinner(false); this.messageService.setDisplayAlert("error", error); this._ngZone.run(() => { //display spinner this.loadingService.displayLoadingSpinner(false); }); }

Es un poco tarde, pero solo quiero dar un ejemplo si alguien quiere usar la API de Google api con ng2.


Incluya el archivo a continuación en su index.html

<script src="https://apis.google.com/js/platform.js" async defer></script>

login.html

<button id="glogin">google login</button>

login.ts

declare const gapi: any; public auth2:any ngAfterViewInit() { gapi.load(''auth2'', () => { this.auth2 = gapi.auth2.init({ client_id: ''788548936361-h264uq1v36c5ddj0hf5fpmh7obks94vh.apps.googleusercontent.com'', cookiepolicy: ''single_host_origin'', scope: ''profile email'' }); this.attachSignin(document.getElementById(''glogin'')); }); } public attachSignin(element) { this.auth2.attachClickHandler(element, {}, (loggedInUser) => { console.log( loggedInUser); }, function (error) { // alert(JSON.stringify(error, undefined, 2)); }); }


Para su primera solución problema es utilizar la función de flecha que conservará contexto de this :

onGoogleLoginSuccess = (loggedInUser) => { this.userAuthToken = loggedInUser.getAuthResponse().id_token; this.userDisplayName = loggedInUser.getBasicProfile().getName(); console.log(this); }

El segundo problema está sucediendo porque los scripts de terceros se ejecutan fuera del contexto de Angular. Angular usa zones modo que cuando ejecuta algo, por ejemplo setTimeout() , que tiene parche de mono para ejecutarse en la zona, se notificará a Angular. Deberías ejecutar jQuery en una zona como esta:

constructor(private zone: NgZone) { this.zone.run(() => { $.proxy(this.onGoogleLoginSuccess, this); }); }

Hay muchas preguntas / respuestas sobre la zona con explicaciones mucho mejores que las mías, si quiere saber más, pero no debería ser un problema para su ejemplo si utiliza la función de flecha.


Pruebe este paquete - npm install angular2-google-login

Github - https://github.com/rudrakshpathak/angular2-google-login

Implementé el inicio de sesión de Google en Angular2. Solo importa el paquete y ya estás listo para comenzar.

Pasos -

import { AuthService, AppGlobals } from ''angular2-google-login'';

Proveedores de suministros: providers: [AuthService];

Constructor - constructor(private _googleAuth: AuthService){}

Establecer ID de cliente de Google - AppGlobals.GOOGLE_CLIENT_ID = ''SECRET_CLIENT_ID'';

Use esto para llamar al servicio -

this._googleAuth.authenticateUser(()=>{ //YOUR_CODE_HERE });

Para cerrar la sesión -

this._googleAuth.userLogout(()=>{ //YOUR_CODE_HERE });