Pertanyaan Google Masuk untuk Situs Web dan Angular 2 menggunakan Typescript


Saya sedang membangun sebuah situs yang memiliki layanan web yang cukup standar untuk menangani ketekunan dan logika bisnis yang rumit. UI yang saya gunakan untuk menggunakan layanan ini Sudut 2 dengan komponen yang ditulis dalam TypeScript.

Daripada membangun sistem otentikasi saya sendiri, saya berharap mengandalkan Google Masuk untuk Situs Web. Idenya adalah bahwa pengguna akan datang ke situs, masuk melalui kerangka kerja yang disediakan di sana dan kemudian mengirim bersama token ID yang dihasilkan, yang server hosting layanan RESTful kemudian dapat memverifikasi.

Di dokumentasi Google Sign-In ada petunjuk untuk membuat tombol masuk melalui JavaScript apa yang perlu terjadi karena tombol login dirender secara dinamis dalam template Angular. Porsi yang relevan dari template:

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

Dan definisi komponen 2 Angular dalam 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);
  }
}

Aliran dasar berjalan:

  1. Angular merender template dan pesan "Halo, kosong!" ditampilkan.
  2. Itu ngAfterViewInit hook dipecat dan gapi.signin2.render(...) metode disebut yang mengonversi div kosong menjadi tombol masuk Google. Ini berfungsi dengan benar dan mengklik tombol itu akan memicu proses masuk.
  3. Ini juga menempel pada komponen onGoogleLoginSuccess metode untuk benar-benar memproses token yang dikembalikan setelah pengguna masuk.
  4. Sudut mendeteksi bahwa userDisplayName properti telah berubah dan memperbarui halaman untuk sekarang menampilkan "Halo, Craig (atau apa pun nama Anda)!".

Masalah pertama yang terjadi adalah di onGoogleLoginSuccess metode. Perhatikan console.log(...) panggilan dalam constructor dan dalam metode itu. Seperti yang diharapkan, yang ada di constructor mengembalikan komponen Sudut. Yang ada di dalam onGoogleLoginSuccess metode, bagaimanapun, mengembalikan JavaScript window obyek.

Jadi sepertinya konteksnya hilang dalam proses melompat ke logika masuk Google sehingga langkah saya berikutnya adalah mencoba menggabungkan jQuery $.proxy panggil untuk mempertahankan konteks yang benar. Jadi saya mengimpor namespace jQuery dengan menambahkan declare var $:any; ke bagian atas komponen dan kemudian mengonversi konten ngAfterViewInit metode menjadi:

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

Setelah menambahkan itu, keduanya console.log panggilan mengembalikan objek yang sama sehingga nilai properti sekarang diperbarui dengan benar. Log pesan kedua menunjukkan objek dengan nilai properti diperbarui yang diharapkan.

Sayangnya, template Angular tidak diperbarui ketika ini terjadi. Saat melakukan debugging, saya menemukan sesuatu yang saya yakini menjelaskan apa yang sedang terjadi. Saya menambahkan baris berikut ke akhir ngAfterViewInit menghubungkan:

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

Ini seharusnya tidak melakukan apa-apa. Itu hanya menunggu lima detik setelah hook berakhir dan kemudian menetapkan nilai properti yang sama dengan dirinya. Namun, dengan garis di tempat itu "Hello, empty!" pesan berubah menjadi "Hello, Craig!" sekitar lima detik setelah halaman dimuat. Ini menyarankan kepada saya bahwa Angular hanya tidak memperhatikan bahwa nilai properti berubah dalam onGoogleLoginSuccess metode. Jadi ketika sesuatu yang lain terjadi untuk memberitahu Angular bahwa nilai properti telah berubah (seperti tugas diri yang tidak berguna di atas), Angular bangun dan perbarui semuanya.

Jelas itu bukan hack yang saya ingin tinggalkan di tempat jadi saya bertanya-tanya apakah ada ahli Angular di luar sana yang bisa memberi saya petunjuk? Apakah ada panggilan yang harus saya lakukan untuk memaksa Angular untuk melihat beberapa properti telah berubah?

DIPERBARUI 2016-02-21 untuk memberikan kejelasan tentang jawaban spesifik yang memecahkan masalah

Saya akhirnya perlu menggunakan kedua bagian dari saran yang diberikan dalam jawaban yang dipilih.

Pertama, persis seperti yang disarankan, saya perlu mengonversi onGoogleLoginSuccess metode untuk menggunakan fungsi panah. Kedua, saya perlu menggunakan sebuah NgZone objek untuk memastikan bahwa pembaruan properti terjadi dalam konteks di mana Sudut sadar. Jadi metode akhirnya berakhir seperti

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

Saya memang perlu mengimpor _zone obyek: import {Component, NgZone} from "angular2/core";

Saya juga perlu menyuntikkannya seperti yang disarankan dalam jawaban melalui contructor kelas: constructor(private _zone: NgZone) { }


32
2018-02-20 23:42


asal


Jawaban:


Untuk solusi masalah pertama Anda adalah menggunakan fungsi panah yang akan melestarikan konteks this :

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

Masalah kedua terjadi karena skrip pihak ketiga berjalan di luar konteks Angular. Penggunaan sudut zones jadi ketika Anda menjalankan sesuatu, misalnya setTimeout(), yang ditambal-monyet untuk berjalan di zona, Angular akan diberi tahu. Anda akan menjalankan jQuery di zona seperti ini:

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

Ada banyak pertanyaan / jawaban tentang zona dengan penjelasan yang jauh lebih baik dari saya, jika Anda ingin tahu lebih banyak, tetapi seharusnya tidak menjadi masalah bagi contoh Anda jika Anda menggunakan fungsi panah.


21
2018-02-21 01:33



Saya membuat komponen masuk-Google jika Anda ingin sebuah contoh.

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

Ini agak terlambat tapi saya hanya ingin memberikan contoh jika seseorang ingin menggunakan api login google dengan ng2.


6
2018-04-01 08:20



Sertakan file di bawah ini di index.html Anda

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

 }

3
2018-03-15 06:48



Coba paket ini - npm install angular2-google-login

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

Saya telah menerapkan login Google di Angular2. Cukup impor paket dan Anda siap untuk pergi.

Langkah -

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

Penyedia pasokan - providers: [AuthService];

Pembuat - constructor(private _googleAuth: AuthService){}

Setel ID klien Google - AppGlobals.GOOGLE_CLIENT_ID = 'SECRET_CLIENT_ID';

Gunakan ini untuk memanggil layanan -

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

Untuk keluar -

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

0
2018-05-12 11:14