Memproses login pengguna di App Engine


Tutorial ini menunjukkan cara mengambil, memverifikasi, dan menyimpan kredensial pihak ketiga menggunakan Identity Platform, lingkungan standar App Engine, dan Datastore.

Dokumen ini akan memandu Anda melalui aplikasi pencatatan sederhana bernama Firestore yang menyimpan catatan pengguna di notebook pribadi mereka. Notebook disimpan per pengguna, dan diidentifikasi oleh ID Identity Platform unik setiap pengguna. Aplikasi tersebut memiliki komponen berikut:

  • Frontend mengonfigurasi antarmuka pengguna login dan mengambil ID Identity Platform. Frontend ini juga menangani perubahan status autentikasi dan memungkinkan pengguna melihat catatan mereka.

  • FirebaseUI adalah solusi open source drop-in yang menyederhanakan tugas autentikasi dan UI. SDK menangani login pengguna, yang menautkan beberapa penyedia ke satu akun, memulihkan sandi, dan lainnya. Layanan ini menerapkan praktik terbaik autentikasi untuk pengalaman login yang lancar dan aman.

  • Backend memverifikasi status autentikasi pengguna dan menampilkan informasi profil pengguna serta catatan pengguna.

Aplikasi ini menyimpan kredensial pengguna di Datastore dengan menggunakan library klien NDB, tetapi Anda dapat menyimpan kredensial tersebut di database pilihan Anda.

Firenotes didasarkan pada framework aplikasi web Flask. Aplikasi contoh menggunakan Flask karena kesederhanaan dan kemudahan penggunaannya, tetapi konsep dan teknologi yang dipelajari dapat diterapkan, terlepas dari framework yang Anda gunakan.

Tujuan

Dengan menyelesaikan tutorial ini, Anda akan menyelesaikan hal berikut:

  • Konfigurasikan antarmuka pengguna dengan FirebaseUI untuk Identity Platform.
  • Mendapatkan token ID Identity Platform dan memverifikasinya menggunakan autentikasi sisi server.
  • Menyimpan kredensial pengguna dan data terkait di Datastore.
  • Membuat kueri database menggunakan library klien NDB.
  • Men-deploy aplikasi ke App Engine.

Biaya

Tutorial ini menggunakan komponen Google Cloud yang dapat ditagih, termasuk:

  • Datastore
  • Identity Platform

Gunakan Kalkulator Harga untuk membuat perkiraan biaya berdasarkan penggunaan yang Anda proyeksikan. Pengguna Google Cloud baru mungkin memenuhi syarat untuk mendapatkan uji coba gratis.

Sebelum memulai

  1. Instal Git, Python 2.7, dan virtualenv. Untuk mengetahui informasi selengkapnya tentang penyiapan lingkungan pengembangan Python, seperti menginstal Python versi terbaru, lihat Menyiapkan Lingkungan Pengembangan Python untuk Google Cloud.
  2. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  3. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  4. Install the Google Cloud CLI.
  5. To initialize the gcloud CLI, run the following command:

    gcloud init
  6. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  7. Install the Google Cloud CLI.
  8. To initialize the gcloud CLI, run the following command:

    gcloud init

Jika Anda telah menginstal dan menginisialisasi SDK ke project yang berbeda, tetapkan project gcloud ke project ID App Engine yang Anda gunakan untuk Firenotes. Baca bagian Mengelola Konfigurasi Google Cloud SDK jika ingin mengetahui perintah khusus untuk mengupdate project dengan alat gcloud.

Membuat clone aplikasi contoh

Untuk mendownload sampel ke komputer lokal:

  1. Buat clone repositori aplikasi contoh ke komputer lokal Anda:

    git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git

    Atau, Anda dapat mendownload contoh sebagai file ZIP dan mengekstraknya.

  2. Buka direktori yang berisi kode contoh:

    cd python-docs-samples/appengine/standard/firebase/firenotes
    

Menambahkan antarmuka pengguna

Untuk mengonfigurasi FirebaseUI untuk Identity Platform dan mengaktifkan penyedia identitas:

  1. Tambahkan Identity Platform ke aplikasi Anda dengan mengikuti langkah-langkah berikut:

    1. Buka Konsol Google Cloud.
      Buka konsol Google Cloud
    2. Pilih project Google Cloud yang ingin Anda gunakan:
      • Jika Anda sudah memiliki project, pilih project tersebut di menu drop-down Select organization di bagian atas halaman.
      • Jika Anda belum memiliki project Google Cloud, buat project baru di Google Cloud Console.
    3. Buka halaman Identity Platform Marketplace di konsol Google Cloud.
      Buka halaman Identity Platform Marketplace
    4. Di halaman Identity Platform Marketplace, klik Aktifkan Identity Pelanggan.
    5. Buka halaman Pengguna Identitas Pelanggan di konsol Google Cloud.
      Buka halaman Pengguna
    6. Di kanan atas, klik detail penyiapan aplikasi.
    7. Salin detail penyiapan aplikasi ke dalam Aplikasi Web Anda.

      // Obtain the following from the "Add Firebase to your web app" dialogue
      // Initialize Firebase
      var config = {
        apiKey: "<API_KEY>",
        authDomain: "<PROJECT_ID>.firebaseapp.com",
        databaseURL: "https://<DATABASE_NAME>.firebaseio.com",
        projectId: "<PROJECT_ID>",
        storageBucket: "<BUCKET>.appspot.com",
        messagingSenderId: "<MESSAGING_SENDER_ID>"
      };
  2. Edit file backend/app.yaml dan masukkan project ID Google Cloud Anda di variabel lingkungan:

    # Copyright 2021 Google LLC
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #      http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    runtime: python27
    api_version: 1
    threadsafe: true
    service: backend
    
    handlers:
    - url: /.*
      script: main.app
    
    env_variables:
      GAE_USE_SOCKETS_HTTPLIB : 'true'
    
  3. Di file frontend/main.js, konfigurasikan widget login FirebaseUI dengan memilih penyedia yang ingin Anda tawarkan kepada pengguna.

    // Firebase log-in widget
    function configureFirebaseLoginWidget() {
      var uiConfig = {
        'signInSuccessUrl': '/',
        'signInOptions': [
          // Leave the lines as is for the providers you want to offer your users.
          firebase.auth.GoogleAuthProvider.PROVIDER_ID,
          firebase.auth.FacebookAuthProvider.PROVIDER_ID,
          firebase.auth.TwitterAuthProvider.PROVIDER_ID,
          firebase.auth.GithubAuthProvider.PROVIDER_ID,
          firebase.auth.EmailAuthProvider.PROVIDER_ID
        ],
        // Terms of service url
        'tosUrl': '<your-tos-url>',
      };
    
      var ui = new firebaseui.auth.AuthUI(firebase.auth());
      ui.start('#firebaseui-auth-container', uiConfig);
    }
  4. Di konsol Google Cloud, aktifkan penyedia yang Anda pilih untuk dipertahankan:

    1. Buka halaman Penyedia Identitas Pelanggan di konsol Google Cloud.
      Buka halaman Penyedia
    2. Klik Tambahkan Penyedia.
    3. Pada menu drop-down Pilih penyedia, pilih penyedia yang ingin Anda gunakan.
    4. Di samping Enabled, klik tombol untuk mengaktifkan penyedia.
      • Untuk penyedia identitas pihak ketiga, masukkan ID dan rahasia penyedia dari situs developer penyedia. Dokumentasi Firebase memberikan petunjuk spesifik di bagian "Sebelum memulai" dalam panduan Facebook, Twitter, dan GitHub.
      • Untuk integrasi SAML dan OIDC, lihat konfigurasi di IdP Anda.
  5. Tambahkan domain Anda ke daftar domain resmi di Identity Platform:

    1. Buka halaman Setelan Identitas Pelanggan di konsol Google Cloud.
      Buka halaman Settings
    2. Di bagian Authorized Domains, klik Add Domain.
    3. Masukkan domain aplikasi Anda dalam format berikut:

      [PROJECT_ID].appspot.com
      

      Jangan sertakan http:// sebelum nama domain.

Menginstal dependensi

  1. Buka direktori backend dan selesaikan penyiapan aplikasi:

    cd backend/
    
  2. Instal dependensi ke direktori lib di project Anda:

    pip install -t lib -r requirements.txt
    
  3. Di appengine_config.py, metode vendor.add() mendaftarkan library dalam direktori lib.

Menjalankan aplikasi secara lokal

Untuk menjalankan aplikasi secara lokal, gunakan server pengembangan lokal App Engine:

  1. Tambahkan URL berikut sebagai backendHostURL di main.js:

    http://localhost:8081

  2. Buka direktori utama aplikasi tersebut. Kemudian, mulai server pengembangan:

    dev_appserver.py frontend/app.yaml backend/app.yaml
    
  3. Buka http://localhost:8080/ di browser web.

Mengautentikasi pengguna di server

Setelah menyiapkan project dan melakukan inisialisasi aplikasi untuk pengembangan, Anda dapat mempelajari kode tersebut untuk memahami cara mengambil dan memverifikasi token ID Identity Platform di server.

Mendapatkan token ID dari Identity Platform

Langkah pertama dalam autentikasi sisi server adalah mengambil token akses untuk diverifikasi. Permintaan Authentication ditangani dengan pemroses onAuthStateChanged() dari Identity Platform:

firebase.auth().onAuthStateChanged(function(user) {
  if (user) {
    $('#logged-out').hide();
    var name = user.displayName;

    /* If the provider gives a display name, use the name for the
    personal welcome message. Otherwise, use the user's email. */
    var welcomeName = name ? name : user.email;

    user.getIdToken().then(function(idToken) {
      userIdToken = idToken;

      /* Now that the user is authenicated, fetch the notes. */
      fetchNotes();

      $('#user').text(welcomeName);
      $('#logged-in').show();

    });

  } else {
    $('#logged-in').hide();
    $('#logged-out').show();

  }
});

Saat pengguna login, metode getToken() Identity Platform di callback menampilkan token ID Identity Platform dalam bentuk Token Web JSON (JWT).

Memverifikasi token di server

Setelah pengguna login, layanan frontend akan mengambil catatan apa pun yang ada di notebook pengguna melalui permintaan GET AJAX. Hal ini memerlukan otorisasi untuk mengakses data pengguna, sehingga JWT dikirim di header Authorization permintaan menggunakan skema Bearer:

// Fetch notes from the backend.
function fetchNotes() {
  $.ajax(backendHostUrl + '/notes', {
    /* Set header for the XMLHttpRequest to get data from the web server
    associated with userIdToken */
    headers: {
      'Authorization': 'Bearer ' + userIdToken
    }
  })

Sebelum klien dapat mengakses data server, server Anda harus memverifikasi bahwa token telah ditandatangani oleh Identity Platform. Anda dapat memverifikasi token ini menggunakan Library Autentikasi Google untuk Python. Gunakan fungsi verify_firebase_token library autentikasi untuk memverifikasi token pemilik dan mengekstrak klaim:

id_token = request.headers["Authorization"].split(" ").pop()
claims = google.oauth2.id_token.verify_firebase_token(
    id_token, HTTP_REQUEST, audience=os.environ.get("GOOGLE_CLOUD_PROJECT")
)
if not claims:
    return "Unauthorized", 401

Setiap penyedia identitas mengirim kumpulan klaim yang berbeda, tetapi masing-masing memiliki setidaknya klaim sub dengan ID pengguna unik dan klaim yang memberikan beberapa informasi profil, seperti name atau email, yang dapat digunakan untuk mempersonalisasi pengalaman pengguna di aplikasi Anda.

Mengelola data pengguna di Datastore

Setelah melakukan autentikasi, Anda harus menyimpan data pengguna agar dapat dipertahankan setelah sesi login berakhir. Bagian berikut menjelaskan cara menyimpan catatan sebagai entity Datastore dan memisahkan entity berdasarkan ID pengguna.

Membuat entity untuk menyimpan data pengguna

Anda dapat membuat entity di Datastore dengan mendeklarasikan class model NDB bersama properti tertentu seperti bilangan bulat atau string. Datastore mengindeks entity berdasarkan jenis; dalam kasus Firenotes, jenis setiap entity adalah Note. Untuk tujuan kueri, setiap Note disimpan dengan nama kunci, yang merupakan ID pengguna yang diperoleh dari klaim sub di bagian sebelumnya.

Kode berikut menunjukkan cara menetapkan properti entity, baik dengan metode konstruktor untuk class model saat entity dibuat maupun melalui penetapan properti individual setelah pembuatan:

data = request.get_json()

# Populates note properties according to the model,
# with the user ID as the key name.
note = Note(parent=ndb.Key(Note, claims["sub"]), message=data["message"])

# Some providers do not provide one of these so either can be used.
note.friendly_id = claims.get("name", claims.get("email", "Unknown"))

Untuk menulis Note yang baru dibuat ke Datastore, panggil metode put() pada objek note.

Mengambil data pengguna

Untuk mengambil data pengguna yang terkait dengan ID pengguna tertentu, gunakan metode query() NDB untuk menelusuri catatan dalam grup entity yang sama di database. Entity dalam grup yang sama, atau jalur ancestor memiliki nama kunci yang sama, yang dalam hal ini adalah ID pengguna.

def query_database(user_id):
    """Fetches all notes associated with user_id.

    Notes are ordered them by date created, with most recent note added
    first.
    """
    ancestor_key = ndb.Key(Note, user_id)
    query = Note.query(ancestor=ancestor_key).order(-Note.created)
    notes = query.fetch()

    note_messages = []

    for note in notes:
        note_messages.append(
            {
                "friendly_id": note.friendly_id,
                "message": note.message,
                "created": note.created,
            }
        )

    return note_messages

Selanjutnya, Anda dapat mengambil data kueri dan menampilkan catatan di klien:

// Fetch notes from the backend.
function fetchNotes() {
  $.ajax(backendHostUrl + '/notes', {
    /* Set header for the XMLHttpRequest to get data from the web server
    associated with userIdToken */
    headers: {
      'Authorization': 'Bearer ' + userIdToken
    }
  }).then(function(data){
    $('#notes-container').empty();
    // Iterate over user data to display user's notes from database.
    data.forEach(function(note){
      $('#notes-container').append($('<p>').text(note.message));
    });
  });
}

Men-deploy aplikasi Anda

Anda telah berhasil mengintegrasikan Identity Platform dengan aplikasi App Engine. Untuk melihat aplikasi Anda berjalan di lingkungan produksi yang aktif:

  1. Ubah URL host backend di main.js menjadi https://backend-dot-[PROJECT_ID].appspot.com. Ganti [PROJECT_ID] dengan project ID Anda.
  2. Deploy aplikasi menggunakan antarmuka command line Google Cloud SDK:

    gcloud app deploy backend/index.yaml frontend/app.yaml backend/app.yaml
    
  3. Lihat permohonan secara langsung di https://[PROJECT_ID].appspot.com.

Pembersihan

Agar tidak menimbulkan biaya pada akun Google Cloud Anda untuk resource yang digunakan dalam tutorial ini, hapus project App Engine Anda:

Menghapus project

Cara termudah untuk menghilangkan penagihan adalah dengan menghapus project yang Anda buat untuk tutorial.

Untuk menghapus project:

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Langkah berikutnya