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 Platform Identitas 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:

  • Mengonfigurasi antarmuka pengguna dengan FirebaseUI untuk Identity Platform.
  • Dapatkan token ID Identity Platform dan verifikasi 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. Login ke akun Google Cloud Anda. Jika Anda baru menggunakan Google Cloud, buat akun untuk mengevaluasi performa produk kami dalam skenario dunia nyata. Pelanggan baru juga mendapatkan kredit gratis senilai $300 untuk menjalankan, menguji, dan men-deploy workload.
  3. Di konsol Google Cloud, pada halaman pemilih project, pilih atau buat project Google Cloud.

    Buka pemilih project

  4. Menginstal Google Cloud CLI.
  5. Untuk initialize gcloud CLI, jalankan perintah berikut:

    gcloud init
  6. Di konsol Google Cloud, pada halaman pemilih project, pilih atau buat project Google Cloud.

    Buka pemilih project

  7. Menginstal Google Cloud CLI.
  8. Untuk initialize gcloud CLI, jalankan perintah berikut:

    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

Guna 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 sudah memiliki project, pilih project tersebut dari menu drop-down Select organization di bagian atas halaman.
      • Jika Anda belum memiliki project Google Cloud, buat project baru di Konsol Google Cloud.
    3. Buka halaman Identity Platform Marketplace di Google Cloud Console.
      Buka halaman Identity Platform Marketplace
    4. Di halaman Identity Platform Marketplace, klik Enable Customer Identity.
    5. Buka halaman Users Customer Identity di Konsol Google Cloud.
      Buka halaman Pengguna
    6. Di kanan atas, klik detail penyiapan aplikasi.
    7. Salin detail penyiapan aplikasi ke 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 disimpan:

    1. Buka halaman Providers Customer Identity di konsol Google Cloud.
      Buka halaman Penyedia
    2. Klik Tambahkan Penyedia.
    3. Pada menu drop-down Select a provider, 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. Dokumen Firebase memberikan petunjuk khusus di bagian "Sebelum memulai" pada panduan Facebook, Twitter, dan GitHub.
      • Untuk integrasi SAML dan OIDC, lihat konfigurasi di IdP Anda.
  5. Tambahkan domain Anda ke daftar domain yang diizinkan di Identity Platform:

    1. Buka halaman Settings Identitas Pelanggan di Konsol Google Cloud.
      Buka halaman Settings
    2. Di bagian Domain yang Diotorisasi, klik Tambahkan 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 menginisialisasi 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 autentikasi 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 akan 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 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. Di konsol Google Cloud, buka halaman Manage resource.

    Buka Manage resource

  2. Pada daftar project, pilih project yang ingin Anda hapus, lalu klik Delete.
  3. Pada dialog, ketik project ID, lalu klik Shut down untuk menghapus project.

Langkah selanjutnya