ย้ายข้อมูลจากบริการผู้ใช้ App Engine ไปยัง Cloud Identity Platform (โมดูล 21)

1. ภาพรวม

ชุดโปรแกรม Codelab สำหรับการย้ายข้อมูลแบบ Serverless (บทแนะนำแบบลงมือทำด้วยตนเอง) และวิดีโอที่เกี่ยวข้องมีจุดประสงค์เพื่อช่วยให้นักพัฒนาแอป Google Cloud Serverless ปรับการดำเนินการให้ทันสมัยได้ด้วยคำแนะนำการย้ายข้อมูลอย่างน้อย 1 รายการ โดยให้ย้ายออกจากบริการเดิมเป็นหลัก การดำเนินการดังกล่าวทำให้แอปพกพาไปได้ทุกที่ รวมถึงมอบตัวเลือกและความยืดหยุ่นที่มากขึ้น ทำให้สามารถผสานรวมและเข้าถึงผลิตภัณฑ์ Cloud ที่หลากหลายยิ่งขึ้น และอัปเกรดเป็นรุ่นภาษาใหม่ๆ ได้ง่ายยิ่งขึ้น แม้ว่าในช่วงแรกจะมุ่งเน้นที่ผู้ใช้ Cloud รุ่นแรกสุด ซึ่งเป็นนักพัฒนา App Engine (สภาพแวดล้อมมาตรฐาน) เป็นหลัก แต่ชุดโซลูชันนี้ก็กว้างพอที่จะรวมแพลตฟอร์มแบบ Serverless อื่นๆ เช่น Cloud Functions และ Cloud Run หรือแพลตฟอร์มอื่นๆ ที่เกี่ยวข้อง

วัตถุประสงค์ของ Codelab นี้คือแสดงให้นักพัฒนา Python 2 App Engine ทราบวิธีย้ายข้อมูลจาก App Engine Users API/service ไปยัง Cloud Identity Platform (GCIP) นอกจากนี้ยังมีการย้ายข้อมูลโดยนัยจาก App Engine NDB ไปยัง Cloud NDB สำหรับการเข้าถึง Datastore (โดยหลักครอบคลุมในโมดูลการย้ายข้อมูล 2) และการอัปเกรดเป็น Python 3

โมดูล 20 จะครอบคลุมวิธีเพิ่มการใช้ Users API ในแอปตัวอย่างของโมดูล 1 ในโมดูลนี้ คุณจะได้ใช้แอปโมดูล 20 ที่เสร็จสมบูรณ์แล้ว และย้ายข้อมูลการใช้งานไปยัง Cloud Identity Platform

คุณจะได้เรียนรู้วิธีต่อไปนี้

  • แทนที่การใช้บริการผู้ใช้ App Engine ด้วย Cloud Identity Platform
  • แทนที่การใช้ App Engine NDB ด้วย Cloud NDB (โปรดดูโมดูล 2 ด้วย)
  • ตั้งค่าผู้ให้บริการข้อมูลประจำตัวในการตรวจสอบสิทธิ์รายอื่นโดยใช้การตรวจสอบสิทธิ์ Firebase
  • ใช้ Cloud Resource Manager API เพื่อรับข้อมูล IAM ของโปรเจ็กต์
  • ใช้ Firebase Admin SDK เพื่อรับข้อมูลผู้ใช้
  • พอร์ตแอปพลิเคชันตัวอย่างไปยัง Python 3

สิ่งที่ต้องมี

แบบสำรวจ

คุณจะใช้บทแนะนำนี้อย่างไร

โปรดอ่านเท่านั้น อ่านและทำแบบฝึกหัด

คุณจะให้คะแนนประสบการณ์การใช้งาน Python อย่างไร

มือใหม่ ระดับกลาง ผู้ชำนาญ

คุณจะให้คะแนนความพึงพอใจในการใช้บริการ Google Cloud อย่างไร

มือใหม่ ระดับกลาง ผู้ชำนาญ

2. ข้อมูลเบื้องต้น

บริการผู้ใช้ App Engine คือระบบการตรวจสอบสิทธิ์ผู้ใช้สำหรับให้แอป App Engine ใช้ ซึ่งทำให้ Google Sign-In เป็นผู้ให้บริการข้อมูลประจำตัว ให้ลิงก์การเข้าสู่ระบบและออกจากระบบที่สะดวกสำหรับการใช้งานในแอปต่างๆ และสนับสนุนแนวคิดเกี่ยวกับผู้ใช้ที่ดูแลระบบและฟังก์ชันเฉพาะผู้ดูแลระบบ หากต้องการปรับปรุงการถ่ายโอนแอปพลิเคชัน Google Cloud ขอแนะนำให้ย้ายข้อมูลจากบริการแพ็กเกจ App Engine แบบเดิมไปยังบริการ Cloud แบบสแตนด์อโลน เช่น จากบริการผู้ใช้ไปยัง Cloud Identity Platform เป็นต้น

Identity Platform ใช้การตรวจสอบสิทธิ์ของ Firebase และเพิ่มฟีเจอร์ระดับองค์กรจำนวนมาก รวมถึงการตรวจสอบสิทธิ์แบบหลายปัจจัย, OIDC และ รองรับ SAML SSO, กลุ่มผู้ใช้หลายกลุ่ม, SLA 99.95% และอื่นๆ นอกจากนี้ยังไฮไลต์ความแตกต่างเหล่านี้ในหน้าการเปรียบเทียบผลิตภัณฑ์ Identity Platform และการตรวจสอบสิทธิ์ Firebase ด้วย ผลิตภัณฑ์ทั้งสองมีฟีเจอร์มากกว่าฟังก์ชันที่ให้บริการโดยบริการผู้ใช้เป็นอย่างมาก

Codelab ของโมดูล 21 นี้จะสาธิตการเปลี่ยนการตรวจสอบสิทธิ์ผู้ใช้ของแอปจากบริการผู้ใช้เป็นฟีเจอร์ของแพลตฟอร์มข้อมูลประจำตัว ซึ่งสอดคล้องกับฟังก์ชันการทำงานที่แสดงในโมดูล 20 มากที่สุด นอกจากนี้ โมดูล 21 ยังมีการย้ายข้อมูลจาก App Engine NDB ไปยัง Cloud NDB สำหรับการเข้าถึง Datastore โดยทำการย้ายข้อมูลโมดูล 2 ซ้ำ

ในขณะที่โค้ดโมดูล 20 มีการ "โฆษณา" ซึ่งเป็นแอปตัวอย่าง Python 2 ตัวแหล่งที่มาเองก็เข้ากันได้กับ Python 2 และ 3 และจะยังคงเป็นเช่นนั้นต่อไปแม้ว่าจะย้ายข้อมูลไปยัง Identity Platform (และ Cloud NDB) ในโมดูล 21 แล้วก็ตาม คุณยังใช้บริการผู้ใช้ต่อไปได้ขณะที่อัปเกรดเป็น Python 3 เนื่องจากการย้ายข้อมูลไปยัง Identity Platform เป็นการดำเนินการที่ไม่บังคับ ดู Codelab ของโมดูล 17 และวิดีโอเพื่อดูวิธีใช้บริการแพ็กเกจต่อขณะอัปเกรดเป็นรันไทม์รุ่นที่ 2 เช่น Python 3

บทแนะนำนี้มีขั้นตอนต่อไปนี้

  1. การตั้งค่า/งานล่วงหน้า
  2. อัปเดตการกำหนดค่า
  3. แก้ไขโค้ดของแอปพลิเคชัน

3. การตั้งค่า/งานล่วงหน้า

ส่วนนี้จะอธิบายวิธี:

  1. ตั้งค่าโปรเจ็กต์ที่อยู่ในระบบคลาวด์
  2. รับแอปตัวอย่างพื้นฐาน
  3. (อีกครั้ง) ติดตั้งใช้งานและตรวจสอบแอปพื้นฐาน
  4. เปิดใช้บริการ/API ใหม่ของ Google Cloud

ขั้นตอนเหล่านี้จะช่วยให้คุณเริ่มต้นจากโค้ดที่ใช้งานได้ซึ่งพร้อมสำหรับการย้ายข้อมูลไปยังบริการระบบคลาวด์แบบสแตนด์อโลน

1. สร้างโปรเจ็กต์

หากคุณทำ Codelab ของโมดูล 20 เสร็จสิ้นแล้ว ให้ใช้โปรเจ็กต์ (และโค้ด) เดียวกันนั้นซ้ำ หรือสร้างโปรเจ็กต์ใหม่หรือใช้โปรเจ็กต์อื่นที่มีอยู่ซ้ำ ตรวจสอบว่าโปรเจ็กต์มีบัญชีสำหรับการเรียกเก็บเงินที่ใช้งานอยู่และแอป App Engine ที่เปิดใช้แล้ว ค้นหารหัสโปรเจ็กต์และเก็บไว้ใกล้ตัวในระหว่าง Codelab นี้และใช้ทุกครั้งที่พบตัวแปร PROJ_ID

2. รับแอปตัวอย่างพื้นฐาน

ข้อกำหนดเบื้องต้นอย่างหนึ่งคือแอป App Engine โมดูล 20 ที่ใช้งานได้ คุณควรทำ Codelab ให้เสร็จ (แนะนำ ลิงก์ด้านบน) หรือคัดลอกโค้ดโมดูล 20 จากที่เก็บ ไม่ว่าคุณจะใช้เครื่องของคุณเองหรือของเรา นี่คือสิ่งที่เราจะเริ่มดำเนินการ ("START") Codelab นี้จะแนะนำการย้ายข้อมูล สรุปด้วยโค้ดที่คล้ายคลึงกับสิ่งที่อยู่ในโฟลเดอร์ที่เก็บโมดูล 21 ("FINISH")

คัดลอกโฟลเดอร์ที่เก็บโมดูล 20 ควรมีลักษณะเหมือนเอาต์พุตด้านล่างและอาจมีโฟลเดอร์ lib หากคุณใช้ Codelab ของโมดูล 20

$ ls
README.md               appengine_config.py     templates
app.yaml                main.py                 requirements.txt

3. (อีกครั้ง) ติดตั้งใช้งานและตรวจสอบแอปพื้นฐาน

ดำเนินการตามขั้นตอนต่อไปนี้เพื่อทำให้แอป Module 20 ใช้งานได้

  1. ลบโฟลเดอร์ lib (หากมี) และเรียกใช้ pip install -t lib -r requirements.txt เพื่อป้อนข้อมูลใหม่ คุณอาจต้องใช้ pip2 หากติดตั้งทั้ง Python 2 และ 3 ไว้
  2. ตรวจสอบว่าคุณได้ติดตั้งและเริ่มต้นเครื่องมือบรรทัดคำสั่ง gcloud และตรวจสอบการใช้งานแล้ว
  3. หากไม่ต้องการป้อน PROJ_ID ด้วยคำสั่ง gcloud แต่ละรายการ ให้ตั้งค่าโปรเจ็กต์ที่อยู่ในระบบคลาวด์ด้วย gcloud config set project PROJ_ID ก่อน
  4. ทำให้แอปตัวอย่างใช้งานได้ด้วย gcloud app deploy
  5. ยืนยันว่าแอปทำงานตามที่คาดไว้โดยไม่มีข้อผิดพลาด หากคุณทำ Codelab ของโมดูล 20 เสร็จสมบูรณ์แล้ว แอปจะแสดงข้อมูลการเข้าสู่ระบบของผู้ใช้ (อีเมลของผู้ใช้, "ป้ายผู้ดูแลระบบ" ที่เป็นไปได้ และปุ่มเข้าสู่ระบบ/ออกจากระบบ) ที่ด้านบนพร้อมกับการเข้าชมล่าสุด (ดังที่แสดงด้านล่าง)

907e64c19ef964f8.png

การลงชื่อเข้าใช้ในฐานะผู้ใช้ทั่วไปจะทำให้ที่อยู่อีเมลของผู้ใช้ปรากฏขึ้น และปุ่ม "ลงชื่อเข้าใช้" ปุ่มเปลี่ยนเป็น "ออกจากระบบ" ปุ่ม:

ad7b59916b69a035.png

การลงชื่อเข้าใช้ในฐานะผู้ใช้ที่ดูแลระบบจะทำให้อีเมลของผู้ใช้แสดงร่วมกับ "(ผู้ดูแลระบบ)" ที่อยู่ติดกัน

867bcb3334149e4.png

4. เปิดใช้ API/บริการ Google Cloud ใหม่

บทนำ

แอปโมดูล 20 ใช้ App Engine NDB และ API ของผู้ใช้ ซึ่งเป็นบริการที่รวมอยู่ในแพ็กเกจที่ไม่ต้องมีการตั้งค่าเพิ่มเติม แต่บริการระบบคลาวด์แบบสแตนด์อโลนต้องใช้ทั้ง Cloud Identity Platform และ Cloud Datastore (ผ่านไลบรารีไคลเอ็นต์ Cloud NDB) นอกจากนี้ เราจำเป็นต้องกำหนดผู้ใช้ที่ดูแลระบบ App Engine จำเป็นต้องใช้ Cloud Resource Manager API ด้วย

ค่าใช้จ่าย

  • App Engine และ Cloud Datastore มี "ฟรีเสมอ" โควต้า และตราบใดที่คุณยังใช้งานไม่เกินขีดจำกัดดังกล่าว คุณไม่ควรเสียค่าใช้จ่ายเมื่อดูบทแนะนำนี้จนจบ โปรดดูที่หน้าราคาของ App Engine และหน้าราคาของ Cloud Datastore สำหรับรายละเอียดเพิ่มเติม
  • การใช้ Cloud Identity Platform จะมีการเรียกเก็บเงินตามจำนวนผู้ใช้ที่ใช้งานอยู่รายเดือน (MAU) หรือการยืนยันการตรวจสอบสิทธิ์ "ฟรี" บางเวอร์ชัน พร้อมใช้งานสำหรับแต่ละรูปแบบการใช้งาน ดูรายละเอียดเพิ่มเติมในหน้าราคา นอกจากนี้ แม้ว่า App Engine และ Cloud Datastore จะกำหนดให้มีการเรียกเก็บเงิน แต่การใช้ GCIP เพียงอย่างเดียวนั้นไม่จำเป็นต้องเปิดใช้การเรียกเก็บเงินตราบใดที่คุณใช้ไม่เกินโควต้ารายวันที่ไม่มีเครื่องมือ ดังนั้นให้พิจารณาวิธีนี้กับโปรเจ็กต์ที่อยู่ในระบบคลาวด์ที่ไม่เกี่ยวข้องกับการเรียกเก็บเงิน/บริการ Cloud APIs
  • ส่วนใหญ่แล้ว คุณสามารถใช้ Cloud Resource Manager API ได้ฟรีตามหน้าราคา

ผู้ใช้เปิดใช้ Cloud API จาก Cloud Console หรือจากบรรทัดคำสั่ง (ผ่านคำสั่ง gcloud ซึ่งเป็นส่วนหนึ่งของ Cloud SDK) ทั้งนี้ขึ้นอยู่กับค่ากำหนดของคุณ เรามาเริ่มจาก Cloud Datastore และ Cloud Resource Manager API กันก่อน

จาก Cloud Console

ไปที่หน้าไลบรารีของตัวจัดการ API (สำหรับโปรเจ็กต์ที่ถูกต้อง) ใน Cloud Console และค้นหา API โดยใช้แถบค้นหา c7a740304e9d35b.png

เปิดใช้ API เหล่านี้

ค้นหาและคลิกปุ่มเปิดใช้สำหรับ API แต่ละรายการแยกกัน คุณอาจได้รับแจ้งให้ใส่ข้อมูลสำหรับการเรียกเก็บเงิน ตัวอย่างเช่น หน้าเว็บสำหรับ Resource Manager API มีดังนี้

fc7bd8f4c49d12e5.png

ปุ่มนี้จะเปลี่ยนเป็น "จัดการ" เมื่อเปิดใช้งานแล้ว (โดยทั่วไปหลังจากไม่กี่วินาที):

8eca12d6cc7b45b0.png

เปิดใช้ Cloud Datastore ในวิธีเดียวกันนี้

83811599b110e46b.png

จากบรรทัดคำสั่ง

แม้ว่าการเปิดใช้ API จากคอนโซลจะทำให้ดูมองเห็นภาพข้อมูล แต่บางโปรแกรมก็เลือกใช้บรรทัดคำสั่งมากกว่า คุณจะได้รับโบนัสเพิ่มจากความสามารถในการเปิดใช้ API จำนวนเท่าใดก็ได้พร้อมกัน ออกคำสั่งนี้เพื่อเปิดใช้ทั้ง Cloud Datastore และ Cloud Resource Manager API และรอให้การดำเนินการเสร็จสมบูรณ์ ดังที่แสดงด้านล่าง

$ gcloud services enable cloudresourcemanager.googleapis.com datastore.googleapis.com
Operation "operations/acat.p2-aaa-bbb-ccc-ddd-eee-ffffff" finished successfully.

ระบบอาจแจ้งให้คุณใส่ข้อมูลสำหรับการเรียกเก็บเงิน

"URL" สำหรับ API แต่ละรายการที่ใช้ในคำสั่งข้างต้นจะเรียกว่าชื่อบริการ API และอยู่ด้านล่างของหน้าไลบรารีสำหรับ API แต่ละรายการ หากต้องการเปิดใช้ Cloud API อื่นๆ สำหรับแอปของคุณเอง คุณสามารถค้นหาชื่อบริการที่เกี่ยวข้องได้ในหน้า API ที่เกี่ยวข้อง คำสั่งนี้จะแสดงชื่อบริการทั้งหมดสำหรับ API ที่คุณเปิดใช้ได้

gcloud services list --available --filter="name:googleapis.com"

ไม่ว่าจะใน Cloud Console หรือบรรทัดคำสั่ง เมื่อคุณดำเนินการตามขั้นตอนข้างต้นเสร็จสมบูรณ์แล้ว ตัวอย่างของเราจะเข้าถึง API เหล่านั้นได้ ขั้นตอนถัดไปคือการเปิดใช้ Cloud Identity Platform และทำการเปลี่ยนแปลงโค้ดที่จำเป็น

เปิดใช้และตั้งค่า Cloud Identity Platform (Cloud Console เท่านั้น)

Cloud Identity Platform คือบริการ Marketplace เนื่องจากแพลตฟอร์มนี้เชื่อมต่อหรือขึ้นอยู่กับทรัพยากรภายนอก Google Cloud เช่น การตรวจสอบสิทธิ์ของ Firebase ปัจจุบันคุณสามารถเปิดใช้บริการ Marketplace ได้จาก Cloud Console เท่านั้น โดยทำตามขั้นตอนต่อไปนี้

  1. ไปที่หน้า Cloud Identity Platform ใน Cloud Marketplace แล้วคลิกปุ่มเปิดใช้ที่นั่น อัปเกรดจากการตรวจสอบสิทธิ์ของ Firebase หากได้รับข้อความแจ้ง ซึ่งจะเป็นการปลดล็อกฟีเจอร์เพิ่มเติม เช่น ฟีเจอร์ที่อธิบายก่อนหน้านี้ในส่วนพื้นหลัง หน้ามาร์เก็ตเพลสที่ไฮไลต์ปุ่มเปิดใช้ 28475f1c9b29de69.png
  2. เมื่อเปิดใช้ Identity Platform แล้ว ระบบจะนำคุณไปยังหน้า Identity Providers โดยอัตโนมัติ หากไม่มี โปรดใช้ลิงก์ที่สะดวกนี้เพื่อไปที่นั่น fc2d92d42a5d1dd7.png
  3. เปิดใช้ผู้ให้บริการการตรวจสอบสิทธิ์ Google หากไม่ได้ตั้งค่าผู้ให้บริการไว้ ให้คลิกเพิ่มผู้ให้บริการ แล้วเลือก Google เมื่อคุณกลับมาที่หน้าจอนี้ คุณควรเปิดใช้รายการ Google Google เป็นผู้ให้บริการตรวจสอบสิทธิ์เพียงรายเดียวที่เราใช้ในบทแนะนำนี้เพื่อมิเรอร์บริการผู้ใช้ App Engine เป็นบริการ Google Sign-In ที่ใช้งานง่าย ในแอปของคุณเอง คุณเปิดใช้ผู้ให้บริการการตรวจสอบสิทธิ์เพิ่มเติมได้
  4. เมื่อคุณเลือกและตั้งค่า Google และผู้ให้บริการการตรวจสอบสิทธิ์รายอื่นที่ต้องการแล้ว ให้คลิกรายละเอียดการตั้งค่าแอปพลิเคชัน และจากหน้าต่างกล่องโต้ตอบการตรวจสอบ ให้คัดลอก apiKey และ authDomain ในออบเจ็กต์ config บนแท็บเว็บ เพื่อบันทึกทั้งคู่ไว้ในที่ที่ปลอดภัย ทำไมไม่คัดลอกทั้งหมดเลยล่ะ ข้อมูลโค้ดในกล่องโต้ตอบนี้เป็นแบบฮาร์ดโค้ดและล้าสมัย ดังนั้นให้บันทึกบิตที่สำคัญที่สุดและใช้ในโค้ดของเราพร้อมกับการใช้ Firebase Auth ที่เกิดขึ้นพร้อมกันมากกว่า เมื่อคุณคัดลอกค่าและบันทึกไว้ในที่ปลอดภัยแล้ว ให้คลิกปุ่มปิด เพื่อตั้งค่าที่จำเป็นทั้งหมดให้เสร็จ bbb09dcdd9be538e.png

4. อัปเดตการกำหนดค่า

การอัปเดตในการกำหนดค่าจะรวมทั้งการเปลี่ยนไฟล์การกำหนดค่าต่างๆ และการสร้างที่เทียบเท่ากับ App Engine แต่ภายในระบบนิเวศของ Cloud Identity Platform

appengine_config.py

  • หากอัปเกรดเป็น Python 3 ให้ลบ appengine_config.py
  • หากมีแผนที่จะปรับเป็น Identity Platform ให้ทันสมัย แต่ใช้งาน Python 2 ไว้ อย่าลบไฟล์ แต่เราจะอัปเดตในภายหลังระหว่างการพอร์ต Python 2

requirements.txt

ไฟล์ requirements.txt ของโมดูล 20 จะแสดงเฉพาะ Flask เท่านั้น สำหรับโมดูล 21 ให้เพิ่มแพ็กเกจต่อไปนี้

เนื้อหาของ requirements.txt ควรมีลักษณะดังนี้

flask
google-auth
google-cloud-ndb
google-cloud-resource-manager
firebase-admin

app.yaml

  • การอัปเกรดเป็น Python 3 จะทำให้ไฟล์ app.yaml ง่ายขึ้น นำทุกอย่างออกยกเว้นคำสั่งรันไทม์ แล้วตั้งค่าเป็น Python 3 เวอร์ชันที่รองรับในปัจจุบัน ปัจจุบันตัวอย่างนี้ใช้เวอร์ชัน 3.10
  • หากคุณยังใช้ Python 2 อยู่ ก็ไม่ต้องดำเนินการใดๆ เลย

ก่อนหน้า:

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

แอปตัวอย่าง Module 20 ไม่มีเครื่องจัดการไฟล์แบบคงที่ หากแอปของคุณมีอยู่แล้ว ให้ปล่อยไว้เช่นนั้น คุณนำเครื่องจัดการสคริปต์ทั้งหมดออกได้ตามต้องการ หรือปล่อยไว้เช่นนั้นเพื่ออ้างอิงก็ได้ตราบใดที่คุณเปลี่ยนแฮนเดิลเป็น auto ตามที่อธิบายไว้ในคู่มือการย้ายข้อมูล app.yaml การเปลี่ยนแปลงเหล่านี้ช่วยให้ app.yaml ที่อัปเดตแล้วสำหรับ Python 3 สามารถทำสิ่งต่างๆ ต่อไปนี้ได้ง่ายขึ้น

หลัง:

runtime: python310

การอัปเดตการกำหนดค่าอื่นๆ

หากมีโฟลเดอร์ lib ให้ลบออก ไม่ว่าจะอยู่ใน Python 2 หรือพอร์ตไปยัง Python 3 ให้ลบออก

5. แก้ไขโค้ดของแอปพลิเคชัน

ส่วนนี้จะแสดงการอัปเดตไฟล์แอปพลิเคชันหลัก main.py แทนที่การใช้บริการ App Engine Users ด้วย Cloud Identity Platform หลังจากอัปเดตแอปพลิเคชันหลัก คุณจะต้องอัปเดตเทมเพลตเว็บ templates/index.html

อัปเดตการนำเข้าและการเริ่มต้น

โปรดทำตามขั้นตอนด้านล่างเพื่ออัปเดตการนำเข้าและเริ่มต้นทรัพยากรของแอปพลิเคชัน

  1. สําหรับการนําเข้า ให้แทนที่ App Engine NDB ด้วย Cloud NDB
  2. นอกจาก Cloud NDB แล้ว ให้นำเข้า Cloud Resource Manager ด้วย
  3. Identity Platform ใช้การตรวจสอบสิทธิ์ Firebase ดังนั้นให้นำเข้า Firebase Admin SDK
  4. Cloud APIs จำเป็นต้องใช้ไคลเอ็นต์ API ดังนั้นให้เริ่มต้นไคลเอ็นต์สำหรับ Cloud NDB ขณะเริ่มต้น Flask

ขณะนำเข้าแพ็กเกจ Cloud Resource Manager ที่นี่เราจะใช้ในภายหลังในการเริ่มต้นแอป ด้านล่างนี้คือการนําเข้าและการเริ่มต้นจากโมดูล 20 ตามด้วยวิธีที่ส่วนต่างๆ ควรดูแลหลังจากนําการเปลี่ยนแปลงข้างต้นไปใช้

ก่อนหน้า:

from flask import Flask, render_template, request
from google.appengine.api import users
from google.appengine.ext import ndb

app = Flask(__name__)

หลัง:

from flask import Flask, render_template, request
from google.auth import default
from google.cloud import ndb, resourcemanager
from firebase_admin import auth, initialize_app

# initialize Flask and Cloud NDB API client
app = Flask(__name__)
ds_client = ndb.Client()

การสนับสนุนสำหรับผู้ดูแลระบบ App Engine

แอปที่รองรับการจดจำผู้ใช้ที่ดูแลระบบนั้นมีองค์ประกอบ 2 อย่าง ได้แก่

  • _get_gae_admins() — ชุดผู้ใช้ที่ดูแลระบบ โทรหนึ่งครั้งและบันทึก
  • is_admin() — ตรวจสอบว่าผู้ใช้ที่ลงชื่อเข้าใช้เป็นผู้ใช้ที่ดูแลระบบหรือไม่ เรียกใช้เมื่อเข้าสู่ระบบของผู้ใช้

ฟังก์ชันยูทิลิตี _get_gae_admins() จะเรียกใช้ Resource Manager API เพื่อดึง Cloud IAM allow-policy ปัจจุบัน นโยบายการอนุญาตจะกำหนดและบังคับใช้บทบาทที่ผู้ใช้หลัก (ผู้ใช้ที่เป็นมนุษย์ บัญชีบริการ เป็นต้น) การตั้งค่าประกอบด้วย

  • กำลังดึงข้อมูลรหัสโปรเจ็กต์ที่อยู่ในระบบคลาวด์ (PROJ_ID)
  • การสร้างไคลเอ็นต์ Resource Manager API (rm_client)
  • การสร้างชุดบทบาทผู้ดูแลระบบ App Engine (_TARGETS) (แบบอ่านอย่างเดียว)

เครื่องมือจัดการทรัพยากรต้องใช้รหัสโปรเจ็กต์ที่อยู่ในระบบคลาวด์ ดังนั้น ให้นำเข้า google.auth.default() และเรียกฟังก์ชันนั้นเพื่อรับรหัสโปรเจ็กต์ การเรียกดังกล่าวมีพารามิเตอร์ที่ดูเหมือน URL แต่เป็นขอบเขตสิทธิ์ OAuth2 เมื่อเรียกใช้แอปในระบบคลาวด์ เช่น ในแอป Compute Engine VM หรือ App Engine จะมีบัญชีบริการเริ่มต้นซึ่งมีสิทธิ์แบบกว้าง เราขอแนะนำให้คุณสร้างบัญชีบริการที่จัดการโดยผู้ใช้ของคุณเอง เพื่อให้สอดคล้องกับแนวทางปฏิบัติแนะนำเกี่ยวกับสิทธิ์ขั้นต่ำที่สุด

สำหรับการเรียก API คุณควรลดขอบเขตแอปลงเป็นระดับขั้นต่ำที่จำเป็นเพื่อให้ทำงานได้อย่างถูกต้อง การเรียก Resource Manager API ที่เรากำลังจะทำคือ get_iam_policy() ซึ่งต้องมีขอบเขตอย่างใดอย่างหนึ่งต่อไปนี้จึงจะทำงานได้

  • https://www.googleapis.com/auth/cloud-platform
  • https://www.googleapis.com/auth/cloud-platform.read-only
  • https://www.googleapis.com/auth/cloudplatformprojects
  • https://www.googleapis.com/auth/cloudplatformprojects.readonly

แอปตัวอย่างต้องการสิทธิ์เข้าถึงนโยบายการอนุญาตระดับอ่านอย่างเดียวเท่านั้น โดยจะไม่แก้ไขนโยบายหรือไม่จําเป็นต้องเข้าถึงโปรเจ็กต์ทั้งหมด ซึ่งหมายความว่าแอปไม่ต้องขอสิทธิ์ใดๆ จาก 3 สิทธิ์แรกที่จำเป็น กฎข้อสุดท้ายคือสิ่งที่ต้องใช้ และนี่คือสิ่งที่เรากำลังนำไปใช้กับแอปตัวอย่าง

ส่วนหลักของฟังก์ชันจะสร้างชุดผู้ใช้ที่ดูแลระบบที่ว่างเปล่า (admins) ดึงข้อมูล allow_policy ผ่าน get_iam_policy() และวนซ้ำการเชื่อมโยงทั้งหมดเพื่อค้นหาบทบาทผู้ดูแลระบบ App Engine โดยเฉพาะ

  • roles/viewer
  • roles/editor
  • roles/owner
  • roles/appengine.appAdmin

สำหรับแต่ละบทบาทเป้าหมายที่พบ ระบบจะจัดเรียงผู้ใช้ที่อยู่ในบทบาทนั้น แล้วเพิ่มลงในกลุ่มผู้ใช้ที่ดูแลระบบโดยรวม และจะสิ้นสุดด้วยการส่งคืนผู้ใช้ที่ดูแลระบบทั้งหมดที่พบและแคชเป็นค่าคงที่ (_ADMINS) ตลอดอายุของอินสแตนซ์ App Engine นี้ เราจะเห็นว่าสายเรียกเข้านี้ดังขึ้นในไม่ช้า

เพิ่มคำจำกัดความของฟังก์ชัน _get_gae_admins() ต่อไปนี้ลงใน main.py ด้านล่างการเริ่มต้นไคลเอ็นต์ Cloud NDB API (ds_client)

def _get_gae_admins():
    'return set of App Engine admins'
    # setup constants for calling Cloud Resource Manager API
    _, PROJ_ID = default(  # Application Default Credentials and project ID
            ['https://www.googleapis.com/auth/cloudplatformprojects.readonly'])
    rm_client = resourcemanager.ProjectsClient()
    _TARGETS = frozenset((     # App Engine admin roles
            'roles/viewer',
            'roles/editor',
            'roles/owner',
            'roles/appengine.appAdmin',
    ))

    # collate users who are members of at least one GAE admin role (_TARGETS)
    admins = set()                      # set of all App Engine admins
    allow_policy = rm_client.get_iam_policy(resource='projects/%s' % PROJ_ID)
    for b in allow_policy.bindings:     # bindings in IAM allow-policy
        if b.role in _TARGETS:          # only look at GAE admin roles
            admins.update(user.split(':', 1).pop() for user in b.members)
    return admins

สิ่งที่จะเกิดขึ้นเมื่อผู้ใช้เข้าสู่ระบบแอป

  1. การตรวจสอบอย่างรวดเร็วจะดำเนินการจากเทมเพลตเว็บหลังจากที่ผู้ใช้ลงชื่อเข้าใช้ Firebase
  2. เมื่อสถานะการตรวจสอบสิทธิ์เปลี่ยนแปลงในเทมเพลต จะมีการเรียก fetch() แบบ Ajax ไปยัง /is_admin ซึ่งมีเครื่องจัดการเป็นฟังก์ชันถัดไป ซึ่งก็คือ is_admin()
  3. ระบบจะส่งโทเค็นรหัส Firebase ในเนื้อหา POST ไปยัง is_admin() ซึ่งจะดึงออกจากส่วนหัวและเรียกใช้ Firebase Admin SDK เพื่อตรวจสอบ หากเป็นผู้ใช้ที่ถูกต้อง ให้ดึงข้อมูลอีเมลของบุคคลนั้นแล้วตรวจสอบว่าเป็นผู้ใช้ที่ดูแลระบบหรือไม่
  4. จากนั้นระบบจะส่งผลลัพธ์บูลีนไปยังเทมเพลตเป็น 200 ที่สำเร็จ

เพิ่ม is_admin() ไปยัง main.py ต่อจาก _get_gae_admins():

@app.route('/is_admin', methods=['POST'])
def is_admin():
    'check if user (via their Firebase ID token) is GAE admin (POST) handler'
    id_token = request.headers.get('Authorization')
    email = auth.verify_id_token(id_token).get('email')
    return {'admin': email in _ADMINS}, 200

โค้ดทั้งหมดจากทั้ง 2 ฟังก์ชันจำเป็นต้องจำลองฟังก์ชันการทำงานที่มีจากบริการผู้ใช้ โดยเฉพาะฟังก์ชัน is_current_user_admin() การเรียกใช้ฟังก์ชันนี้ในโมดูล 20 เป็นการดำเนินการที่ยากทั้งหมด ซึ่งต่างจากโมดูล 21 ที่เราใช้โซลูชันทดแทน ข่าวดีคือแอปไม่จำเป็นต้องพึ่งบริการเฉพาะสำหรับ App Engine อีกต่อไป ซึ่งหมายความว่าคุณสามารถย้ายแอปไปยัง Cloud Run หรือบริการอื่นๆ ได้ นอกจากนี้ คุณยังเปลี่ยนคำจำกัดความของ "ผู้ใช้ที่ดูแลระบบ" ได้ด้วย สำหรับแอปของคุณเองได้ง่ายๆ เพียงเปลี่ยนเป็นบทบาทที่ต้องการใน _TARGETS ในขณะที่บริการผู้ใช้ได้รับการฮาร์ดโค้ดสำหรับบทบาทผู้ดูแลระบบ App Engine

เริ่มต้น Firebase Auth และแคชผู้ใช้ที่ดูแลระบบ App Engine

เราสามารถเริ่มต้น Firebase Auth ได้ที่ด้านบนสุดใกล้กับจุดเดียวกับที่แอป Flask ได้รับการเริ่มต้น และสร้างไคลเอ็นต์ Cloud NDB API แล้ว แต่ไม่จำเป็นต้องกำหนดค่าจนกว่าจะระบุโค้ดผู้ดูแลระบบได้ครบทั้งหมดแล้ว ในทำนองเดียวกัน เมื่อกำหนด _get_gae_admins() แล้ว ให้เรียกใช้เพื่อแคชรายชื่อผู้ใช้ที่ดูแลระบบ

เพิ่มบรรทัดต่อไปนี้ในส่วนเนื้อหาของฟังก์ชัน is_admin()

# initialize Firebase and fetch set of App Engine admins
initialize_app()
_ADMINS = _get_gae_admins()

ไปที่การอัปเดตโมเดลข้อมูล

โมเดลข้อมูล Visit จะไม่เปลี่ยนแปลง การเข้าถึงพื้นที่เก็บข้อมูลต้องใช้การจัดการบริบทของไคลเอ็นต์ Cloud NDB API อย่างชัดเจน ds_client.context() ในโค้ด การดำเนินการนี้หมายความว่าคุณรวมการเรียกใช้ Datastore ทั้งใน store_visit() และ fetch_visits() ภายในบล็อก Python with การอัปเดตนี้เหมือนกับโมดูล 2 ทำการเปลี่ยนแปลงดังต่อไปนี้

ก่อนหน้า:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    'get most recent visits'
    return Visit.query().order(-Visit.timestamp).fetch(limit)

หลัง:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    'get most recent visits'
    with ds_client.context():
        return Visit.query().order(-Visit.timestamp).fetch(limit)

ย้ายตรรกะการเข้าสู่ระบบของผู้ใช้ไปยังเทมเพลตเว็บ

บริการผู้ใช้ App Engine จะอยู่ในฝั่งเซิร์ฟเวอร์ ขณะที่ Firebase Auth และ Cloud Identity Platform จะเป็นฝั่งไคลเอ็นต์เป็นส่วนใหญ่ ทำให้โค้ดการจัดการผู้ใช้ในแอปโมดูล 20 จำนวนมากย้ายไปที่เทมเพลตเว็บสำหรับโมดูล 21

ใน main.py บริบทเว็บจะส่งข้อมูลที่สำคัญ 5 อย่างไปยังเทมเพลต 4 รายการแรกที่ระบุไว้จะเกี่ยวข้องกับการจัดการผู้ใช้และแตกต่างกันโดยขึ้นอยู่กับว่าผู้ใช้ลงชื่อเข้าใช้หรือไม่

  • who — อีเมลของผู้ใช้ หากลงชื่อเข้าใช้หรือผู้ใช้
  • admin — ป้าย (ผู้ดูแลระบบ) หากผู้ใช้ลงชื่อเข้าใช้เป็นผู้ดูแลระบบ
  • sign — แสดงปุ่มเข้าสู่ระบบหรือออกจากระบบ
  • link — ลิงก์ลงชื่อเข้าใช้หรือออกจากระบบเมื่อคลิกปุ่ม
  • visits — การเข้าชมล่าสุด

ก่อนหน้า:

@app.route('/')
def root():
    'main application (GET) handler'
    store_visit(request.remote_addr, request.user_agent)
    visits = fetch_visits(10)

    # put together users context for web template
    user = users.get_current_user()
    context = {  # logged in
        'who':   user.nickname(),
        'admin': '(admin)' if users.is_current_user_admin() else '',
        'sign':  'Logout',
        'link':  '/_ah/logout?continue=%s://%s/' % (
                      request.environ['wsgi.url_scheme'],
                      request.environ['HTTP_HOST'],
                  ),  # alternative to users.create_logout_url()
    } if user else {  # not logged in
        'who':   'user',
        'admin': '',
        'sign':  'Login',
        'link':  users.create_login_url('/'),
    }

    # add visits to context and render template
    context['visits'] = visits  # display whether logged in or not
    return render_template('index.html', **context)

การจัดการผู้ใช้ทั้งหมดจะย้ายไปอยู่ในเทมเพลตเว็บ เราจึงเหลือแค่การเข้าชมเท่านั้น โดยนำเครื่องจัดการหลักกลับมาใช้แอปโมดูล 1 แบบเดิม

หลัง:

@app.route('/')
def root():
    'main application (GET) handler'
    store_visit(request.remote_addr, request.user_agent)
    visits = fetch_visits(10)
    return render_template('index.html', visits=visits)

อัปเดตเทมเพลตเว็บ

การอัปเดตทั้งหมดจากส่วนก่อนหน้าในเทมเพลตมีลักษณะอย่างไร โดยหลักๆ แล้วจะเป็นการย้ายการจัดการผู้ใช้จากแอปไปยัง Firebase Auth ที่ทำงานในเทมเพลต และพอร์ตบางส่วนของโค้ดทั้งหมดที่เราย้ายไปไว้ใน JavaScript เราพบว่า main.py หดตัวลงเล็กน้อย จึงคาดว่าจะมีการเติบโตที่คล้ายกันใน templates/index.html

ก่อนหน้า:

<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
</head>
<body>
<p>
Welcome, {{ who }} <code>{{ admin }}</code>
<button id="logbtn">{{ sign }}</button>
</p><hr>

<h1>VisitMe example</h1>
<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
    <li>{{ visit.timestamp.ctime() }} from {{ visit.visitor }}</li>
{% endfor %}
</ul>

<script>
document.getElementById("logbtn").onclick = () => {
    window.location.href = '{{ link }}';
};
</script>
</body>
</html>

แทนที่เทมเพลตเว็บทั้งหมดด้วยเนื้อหาด้านล่าง

หลัง:

<!doctype html>
<html>
<head>
<title>VisitMe Example</title>

<script type="module">
// import Firebase module attributes
import {
        initializeApp
} from "https://www.gstatic.com/firebasejs/9.10.0/firebase-app.js";
import {
        GoogleAuthProvider,
        getAuth,
        onAuthStateChanged,
        signInWithPopup,
        signOut
} from "https://www.gstatic.com/firebasejs/9.10.0/firebase-auth.js";

// Firebase config:
// 1a. Go to: console.cloud.google.com/customer-identity/providers
// 1b. May be prompted to enable GCIP and upgrade from Firebase
// 2. Click: "Application Setup Details" button
// 3. Copy: 'apiKey' and 'authDomain' from 'config' variable
var firebaseConfig = {
        apiKey: "YOUR_API_KEY",
        authDomain: "YOUR_AUTH_DOMAIN",
};

// initialize Firebase app & auth components
initializeApp(firebaseConfig);
var auth = getAuth();
var provider = new GoogleAuthProvider();
//provider.setCustomParameters({prompt: 'select_account'});

// define login and logout button functions
function login() {
    signInWithPopup(auth, provider);
};

function logout() {
    signOut(auth);
};

// check if admin & switch to logout button on login; reset everything on logout
onAuthStateChanged(auth, async (user) => {
    if (user && user != null) {
        var email = user.email;
        who.innerHTML = email;
        logbtn.onclick = logout;
        logbtn.innerHTML = "Logout";
        var idToken = await user.getIdToken();
        var rsp = await fetch("/is_admin", {
                method: "POST",
                headers: {Authorization: idToken}
        });
        var data = await rsp.json();
        if (data.admin) {
            admin.style.display = "inline";
        }
    } else {
        who.innerHTML = "user";
        admin.style.display = "none";
        logbtn.onclick = login;
        logbtn.innerHTML = "Login";
    }
});
</script>
</head>

<body>
<p>
Welcome, <span id="who"></span> <span id="admin"><code>(admin)</code></span>
<button id="logbtn"></button>
</p><hr>

<h1>VisitMe example</h1>
<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
    <li>{{ visit.timestamp.ctime() }} from {{ visit.visitor }}</li>
{% endfor %}
</ul>

<script>
var who    = document.getElementById("who");
var admin  = document.getElementById("admin");
var logbtn = document.getElementById("logbtn");
</script>
</body>
</html>

ซึ่งมีหลายองค์ประกอบในเนื้อหา HTML นี้ ลองมาพิจารณากันทีละส่วน

การนําเข้า Firebase

ขณะที่ยังอยู่ในส่วนหัวของเอกสาร HTML เมื่อพ้นชื่อหน้าแล้ว ให้นำเข้าคอมโพเนนต์ Firebase ที่จำเป็น ตอนนี้คอมโพเนนต์ Firebase แบ่งออกเป็นหลายโมดูลเพื่อประสิทธิภาพแล้ว โค้ดสำหรับเริ่มต้น Firebase จะนำเข้าจากโมดูลแอป Firebase หลัก ในขณะที่ฟังก์ชันที่จัดการการตรวจสอบสิทธิ์ของ Firebase, Google ในฐานะผู้ให้บริการการตรวจสอบสิทธิ์, การลงชื่อเข้าใช้และออกจากระบบ และเปลี่ยน "callback" สถานะการตรวจสอบสิทธิ์ นำเข้าทั้งหมดจากโมดูลการตรวจสอบสิทธิ์ Firebase

<!doctype html>
<html>
<head>
<title>VisitMe Example</title>

<script type="module">
// import Firebase module attributes
import {
        initializeApp
} from "https://www.gstatic.com/firebasejs/9.10.0/firebase-app.js";
import {
        GoogleAuthProvider,
        getAuth,
        onAuthStateChanged,
        signInWithPopup,
        signOut
} from "https://www.gstatic.com/firebasejs/9.10.0/firebase-auth.js";

การกำหนดค่า Firebase

ก่อนหน้านี้ระหว่างการตั้งค่า Identity Platform ของบทแนะนำนี้ คุณได้บันทึก apiKey และ authDomain จากกล่องโต้ตอบรายละเอียดการตั้งค่าแอปพลิเคชัน เพิ่มค่าเหล่านั้นลงในตัวแปร firebaseConfig ในส่วนถัดไปนี้ ลิงก์ไปยังวิธีการแบบละเอียดจะอยู่ในความคิดเห็น

// Firebase config:
// 1a. Go to: console.cloud.google.com/customer-identity/providers
// 1b. May be prompted to enable GCIP and upgrade from Firebase
// 2. Click: "Application Setup Details" button
// 3. Copy: 'apiKey' and 'authDomain' from 'config' variable
var firebaseConfig = {
        apiKey: "YOUR_API_KEY",
        authDomain: "YOUR_AUTH_DOMAIN",
};

การเริ่มต้น Firebase

ส่วนถัดไปจะเริ่มต้น Firebase ด้วยข้อมูลการกำหนดค่านี้

// initialize Firebase app & auth components
initializeApp(firebaseConfig);
var auth = getAuth();
var provider = new GoogleAuthProvider();
//provider.setCustomParameters({prompt: 'select_account'});

การตั้งค่านี้จะกำหนดความสามารถในการใช้ Google เป็นผู้ให้บริการตรวจสอบสิทธิ์ และมอบตัวเลือกให้แสดงความคิดเห็นเพื่อแสดงตัวเลือกบัญชีแม้ว่าจะมีบัญชี Google เพียงบัญชีเดียวที่ลงทะเบียนในเซสชันเบราว์เซอร์ของคุณ กล่าวคือ เมื่อคุณมีหลายบัญชี ระบบจะแสดง "เครื่องมือเลือกบัญชี" นี้ ตามที่คาดไว้: a38369389b7c4c7e.png อย่างไรก็ตาม หากมีผู้ใช้เพียงคนเดียวในเซสชัน กระบวนการเข้าสู่ระบบจะดำเนินการโดยอัตโนมัติโดยไม่ต้องมีการโต้ตอบจากผู้ใช้ (จากนั้นป๊อปอัปก็จะหายไป) คุณสามารถบังคับให้กล่องโต้ตอบเครื่องมือเลือกบัญชีแสดงขึ้นสำหรับผู้ใช้ 1 ราย (แทนการเข้าสู่ระบบแอปทันที) ได้โดยยกเลิกการใส่หมายเหตุบรรทัดพารามิเตอร์ที่กำหนดเอง หากเปิดใช้ แม้แต่การเข้าสู่ระบบแบบผู้ใช้รายเดียว ระบบจะแสดงเครื่องมือเลือกบัญชี: b75624cb68d94557.png

ฟังก์ชันการเข้าสู่ระบบและออกจากระบบ

โค้ดบรรทัดถัดไปจะประกอบกันเป็นฟังก์ชันสำหรับการคลิกปุ่มเข้าสู่ระบบหรือออกจากระบบ

// define login and logout button functions
function login() {
    signInWithPopup(auth, provider);
};

function logout() {
    signOut(auth);
};

การดำเนินการลงชื่อเข้าใช้และออกจากระบบ

ส่วนหลักสุดท้ายในบล็อก <script> นี้คือฟังก์ชันที่เรียกใช้เมื่อมีการเปลี่ยนแปลงการตรวจสอบสิทธิ์ทุกครั้ง (ลงชื่อเข้าใช้หรือออกจากระบบ)

// check if admin & switch to logout button on login; reset everything on logout
onAuthStateChanged(auth, async (user) => {
    if (user && user != null) {
        var email = user.email;
        who.innerHTML = email;
        logbtn.onclick = logout;
        logbtn.innerHTML = "Logout";
        var idToken = await user.getIdToken();
        var rsp = await fetch("/is_admin", {
                method: "POST",
                headers: {Authorization: idToken}
        });
        var data = await rsp.json();
        if (data.admin) {
            admin.style.display = "inline";
        }
    } else {
        who.innerHTML = "user";
        admin.style.display = "none";
        logbtn.onclick = login;
        logbtn.innerHTML = "Login";
    }
});
</script>
</head>

โค้ดในโมดูล 20 ที่กำหนดว่าจะส่ง "ผู้ใช้ที่เข้าสู่ระบบ" หรือไม่ บริบทเทมเพลตเทียบกับ "ผู้ใช้ออกจากระบบ" มีการเปลี่ยนแปลงที่นี่ เงื่อนไขตามเงื่อนไขที่ด้านบนจะแสดงเป็น true หากผู้ใช้เข้าสู่ระบบสำเร็จ ซึ่งจะทริกเกอร์การดำเนินการต่อไปนี้

  1. ตั้งค่าอีเมลของผู้ใช้ให้แสดง
  2. ปุ่มเข้าสู่ระบบจะเปลี่ยนเป็นออกจากระบบ
  3. การเรียก /is_admin แบบ Ajax ใช้เพื่อเลือกว่าจะแสดงป้ายผู้ดูแลระบบ (admin) หรือไม่

เมื่อผู้ใช้ออกจากระบบ ระบบจะดำเนินการตามวรรค else เพื่อรีเซ็ตข้อมูลผู้ใช้ทั้งหมด ดังนี้

  1. ตั้งชื่อผู้ใช้เป็น user แล้ว
  2. นำป้ายผู้ดูแลระบบออกแล้ว
  3. ปุ่มออกจากระบบเปลี่ยนกลับไปเป็นเข้าสู่ระบบ

ตัวแปรเทมเพลต

หลังจากส่วนหัวสิ้นสุดลง ส่วนเนื้อหาหลักจะเริ่มต้นด้วยตัวแปรเทมเพลตซึ่งถูกแทนที่ด้วยองค์ประกอบ HTML ที่เปลี่ยนแปลงตามความจำเป็น ดังนี้

  1. ชื่อผู้ใช้ที่แสดง
  2. ป้ายผู้ดูแลระบบ (admin) (หากมี)
  3. ปุ่มเข้าสู่ระบบหรือออกจากระบบ
<body>
<p>
Welcome, <span id="who"></span> <span id="admin"><code>(admin)</code></span>
<button id="logbtn"></button>
</p><hr>

การเข้าชมล่าสุดและตัวแปรองค์ประกอบ HTML

โค้ดการเข้าชมล่าสุดจะไม่เปลี่ยนแปลง และบล็อก <script> สุดท้ายจะตั้งค่าตัวแปรสำหรับองค์ประกอบ HTML ที่เปลี่ยนแปลงสำหรับการลงชื่อเข้าใช้และออกจากระบบตามที่แสดงอยู่ด้านบน

<h1>VisitMe example</h1>
<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
    <li>{{ visit.timestamp.ctime() }} from {{ visit.visitor }}</li>
{% endfor %}
</ul>

<script>
var who    = document.getElementById("who");
var admin  = document.getElementById("admin");
var logbtn = document.getElementById("logbtn");
</script>
</body>
</html>

การดําเนินการนี้สรุปการเปลี่ยนแปลงที่จําเป็นในแอปพลิเคชันและเทมเพลตเว็บเพื่อเปลี่ยนจาก App Engine NDB และ Users API เป็น Cloud NDB และ Identity Platform รวมถึงการอัปเกรดเป็น Python 3 ขอแสดงความยินดีกับการใช้แอปตัวอย่างโมดูล 21 ใหม่ คุณตรวจสอบเวอร์ชันได้ในโฟลเดอร์ที่เก็บโมดูล 21b

ส่วนถัดไปของ Codelab จะมีหรือไม่ก็ได้ (*) และเฉพาะสำหรับผู้ใช้ที่แอปจะต้องอยู่ใน Python 2 เท่านั้น ซึ่งจะนำคุณผ่านขั้นตอนที่จำเป็นเพื่อไปยังแอป Python 2 Module 21 ที่ใช้งานได้

6. *แบ็กพอร์ต Python 2

ส่วนที่ไม่บังคับนี้มีไว้สำหรับนักพัฒนาแอปที่ย้ายข้อมูล Identity Platform แต่ต้องเรียกใช้ในรันไทม์ของ Python 2 ต่อไป หากนี่ไม่ใช่ข้อกังวลสำหรับคุณ ให้ข้ามส่วนนี้

หากต้องการสร้างแอปโมดูล 21 เวอร์ชัน Python 2 ที่ใช้งานได้ คุณต้องมีสิ่งต่อไปนี้

  1. ข้อกำหนดรันไทม์: ไฟล์การกำหนดค่าที่รองรับ Python 2 และการเปลี่ยนแปลงที่จำเป็นในแอปพลิเคชันหลักเพื่อหลีกเลี่ยงความไม่เข้ากันของ Python 3
  2. การเปลี่ยนแปลงไลบรารีเล็กน้อย: เลิกใช้งาน Python 2 ไปแล้วก่อนที่จะเพิ่มฟีเจอร์ที่จำเป็นบางรายการลงในไลบรารีของไคลเอ็นต์ Resource Manager ด้วยเหตุนี้ คุณจึงต้องมีทางเลือกอื่นในการเข้าถึงฟังก์ชันการทำงานที่ขาดหายไป

เรามาลองทําตามขั้นตอนเหล่านั้นกัน โดยเริ่มจากการกําหนดค่า

กู้คืน appengine_config.py

ก่อนหน้านี้ในบทแนะนำนี้ คุณได้รับคำแนะนำให้ลบ appengine_config.py เนื่องจากรันไทม์ของ Python 3 App Engine ไม่ได้ใช้งานอยู่ สำหรับ Python 2 ไม่เพียงแต่ต้องเก็บรักษาไว้ แต่ต้องอัปเดตโมดูล 20 appengine_config.py ให้รองรับการใช้ไลบรารีของบุคคลที่สามในตัว ซึ่งได้แก่ grpcio และ setuptools คุณจำเป็นต้องใช้แพ็กเกจดังกล่าวทุกครั้งที่แอป App Engine ใช้ไลบรารีของไคลเอ็นต์ระบบคลาวด์ เช่น แพ็กเกจสำหรับ Cloud NDB และ Cloud Resource Manager

คุณจะเพิ่มแพ็กเกจเหล่านั้นไปยัง app.yaml ในอีกสักครู่ แต่เพื่อให้แอปเข้าถึงแพ็กเกจได้ จะต้องมีการเรียกใช้ฟังก์ชัน pkg_resources.working_set.add_entry() จาก setuptools ซึ่งจะทำให้ไลบรารีของบุคคลที่สามที่คัดลอก (รวมกลุ่มด้วยตนเองหรือแบบผู้ให้บริการ) ที่ติดตั้งในโฟลเดอร์ lib สื่อสารกับไลบรารีในตัวได้

นำการอัปเดตต่อไปนี้ไปใช้กับไฟล์ appengine_config.py เพื่อให้การเปลี่ยนแปลงเหล่านี้มีผล

ก่อนหน้า:

from google.appengine.ext import vendor

# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)

โค้ดนี้เพียงอย่างเดียวไม่เพียงพอที่จะรองรับการใช้งาน setuptools และ grpcio ต้องใช้เพิ่มอีก 2-3 บรรทัด ดังนั้น ให้อัปเดต appengine_config.py ให้มีลักษณะดังนี้

หลัง:

import pkg_resources
from google.appengine.ext import vendor

# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)
# Add libraries to pkg_resources working set to find the distribution.
pkg_resources.working_set.add_entry(PATH)

ดูรายละเอียดเพิ่มเติมเกี่ยวกับการเปลี่ยนแปลงที่จําเป็นเพื่อรองรับไลบรารีของไคลเอ็นต์ Cloud ได้ในเอกสารประกอบของการย้ายข้อมูลในแพ็กเกจบริการ

app.yaml

ไฟล์ app.yaml ต้องเปลี่ยนกลับไปเป็นไฟล์ที่รองรับ Python 2 เช่นเดียวกับ appengine_config.py เรามาเริ่มกันที่โมดูล 20 app.yaml เดิมกันก่อน:

ก่อนหน้า:

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

นอกเหนือจาก setuptools และ grpcio ตามที่กล่าวไปก่อนหน้านี้แล้ว ยังมีทรัพยากร Dependency (ที่ไม่เกี่ยวข้องกับการย้ายข้อมูล Identity Platform อย่างชัดเจน) ที่กำหนดให้ใช้ไลบรารีของไคลเอ็นต์ Cloud Storage และต้องการแพ็กเกจของบุคคลที่สามอีก 1 รายการ ซึ่งก็คือ ssl เพิ่มทั้ง 3 รายการในส่วน libraries ใหม่ โดยเลือก "ล่าสุด" เวอร์ชันที่พร้อมใช้งานของแพ็กเกจเหล่านั้น ไปยัง app.yaml:

หลัง:

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

libraries:
- name: grpcio
  version: latest
- name: setuptools
  version: latest
- name: ssl
  version: latest

requirements.txt

สำหรับโมดูล 21 เราได้เพิ่ม Google Auth, Cloud NDB, Cloud Resource Manager และ Firebase Admin SDK ลงใน Python 3 requirements.txt สถานการณ์ของ Python 2 มีความซับซ้อนมากขึ้นดังนี้

  • Resource Manager API มีฟังก์ชันการทำงานของนโยบายการอนุญาตที่จำเป็นสำหรับแอปตัวอย่าง ขออภัย การสนับสนุนนี้ยังไม่พร้อมใช้งานในเวอร์ชันสุดท้ายสำหรับ Python 2 ของไลบรารีของไคลเอ็นต์ Cloud Resource Manager (ใช้ได้เฉพาะในเวอร์ชัน Python 3)
  • ด้วยเหตุนี้ จึงต้องเป็นทางเลือกในการเข้าถึงฟีเจอร์นี้จาก API โซลูชันคือการใช้ไลบรารีของไคลเอ็นต์ Google APIs ระดับล่างเพื่อสื่อสารกับ API หากต้องการเปลี่ยนไปใช้ไลบรารีของไคลเอ็นต์นี้ ให้แทนที่ google-cloud-resource-manager ด้วยแพ็กเกจ google-api-python-client ระดับล่าง
  • เนื่องจาก Python 2 ได้หยุดให้บริการแล้ว กราฟทรัพยากร Dependency ที่รองรับโมดูล 21 จึงต้องล็อกแพ็กเกจบางรายการเป็นเวอร์ชันที่เฉพาะเจาะจง ต้องมีการเรียกแพ็กเกจบางรายการออก แม้จะไม่ได้ระบุไว้ใน Python 3 app.yaml ก็ตาม

ก่อนหน้า:

flask

เริ่มต้นด้วยโมดูล 20 requirements.txt โปรดอัปเดตเป็นรายการต่อไปนี้สำหรับแอปโมดูล 21 ที่ใช้งานได้

หลัง:

grpcio==1.0.0
protobuf<3.18.0
six>=1.13.0
flask
google-gax<0.13.0
google-api-core==1.31.1
google-api-python-client<=1.11.0
google-auth<2.0dev
google-cloud-datastore==1.15.3
google-cloud-firestore==1.9.0
google-cloud-ndb
google-cloud-pubsub==1.7.0
firebase-admin

ระบบจะอัปเดตหมายเลขแพ็กเกจและหมายเลขเวอร์ชันในที่เก็บเมื่อทรัพยากร Dependency มีการเปลี่ยนแปลง แต่ app.yaml นี้ก็เพียงพอแล้วสำหรับแอปที่ทำงานได้ ณ เวลาที่เขียนนี้

การอัปเดตการกำหนดค่าอื่นๆ

หากคุณยังไม่ได้ลบโฟลเดอร์ lib ออกจาก Codelab ก่อนหน้านี้ ให้ลบตอนนี้ เมื่อใช้ requirements.txt ที่อัปเดตใหม่ ให้ส่งคำสั่งที่คุ้นเคยนี้เพื่อติดตั้งข้อกำหนดเหล่านี้ลงใน lib

pip install -t lib -r requirements.txt  # or pip2

หากติดตั้งทั้ง Python 2 และ 3 ไว้ในระบบการพัฒนาแล้ว คุณอาจต้องใช้ pip2 แทน pip

แก้ไขโค้ดของแอปพลิเคชัน

โชคดีที่การเปลี่ยนแปลงที่จำเป็นส่วนใหญ่อยู่ในไฟล์การกำหนดค่า การเปลี่ยนแปลงเพียงอย่างเดียวที่จำเป็นในโค้ดของแอปพลิเคชันคือการอัปเดตเล็กน้อยเพื่อใช้ไลบรารีของไคลเอ็นต์ Google API ระดับล่างแทนไลบรารีของไคลเอ็นต์ Resource Manager ในการเข้าถึง API ไม่ต้องอัปเดตเทมเพลตเว็บ templates/index.html

อัปเดตการนำเข้าและการเริ่มต้น

แทนที่ไลบรารีของไคลเอ็นต์ Resource Manager (google.cloud.resourcemanager) ด้วยไลบรารีของไคลเอ็นต์ Google APIs (googleapiclient.discovery) ตามที่แสดงด้านล่าง

ก่อนหน้า:

from flask import Flask, render_template, request
from google.auth import default
from google.cloud import ndb, resourcemanager
from firebase_admin import auth, initialize_app

หลัง:

from flask import Flask, render_template, request
from google.auth import default
from google.cloud import ndb
from googleapiclient import discovery
from firebase_admin import auth, initialize_app

การสนับสนุนสำหรับผู้ดูแลระบบ App Engine

ต้องมีการเปลี่ยนแปลงบางอย่างใน _get_gae_admins() เพื่อรองรับการใช้ไลบรารีของไคลเอ็นต์ระดับล่าง เรามาพูดคุยถึงสิ่งที่เปลี่ยนแปลงก่อนแล้วจึงมอบโค้ดทั้งหมดที่จะอัปเดต

โค้ด Python 2 ต้องใช้ทั้งข้อมูลเข้าสู่ระบบและรหัสโปรเจ็กต์ที่แสดงผลจาก google.auth.default() ข้อมูลเข้าสู่ระบบไม่ได้ใช้ใน Python 3 จึงกำหนดให้กับตัวแปรจำลองขีดล่าง ( _) ทั่วไป เนื่องจากจำเป็นสำหรับเวอร์ชัน Python 2 ให้เปลี่ยนขีดล่างเป็น CREDS นอกจากนี้ คุณจะสร้างปลายทางบริการของ API ในลักษณะเดียวกับไคลเอ็นต์ API แทนการสร้างไคลเอ็นต์ Resource Manager API เราจึงใช้ชื่อตัวแปรเดิม (rm_client) ความแตกต่างอย่างหนึ่งคือการสร้างปลายทางบริการต้องใช้ข้อมูลเข้าสู่ระบบ (CREDS)

การเปลี่ยนแปลงดังกล่าวจะแสดงอยู่ในโค้ดด้านล่าง

ก่อนหน้า:

_, PROJ_ID = default(  # Application Default Credentials and project ID
        ['https://www.googleapis.com/auth/cloudplatformprojects.readonly'])
rm_client = resourcemanager.ProjectsClient()

หลัง:

CREDS, PROJ_ID = default(  # Application Default Credentials and project ID
        ['https://www.googleapis.com/auth/cloud-platform'])
rm_client = discovery.build('cloudresourcemanager', 'v1', credentials=CREDS)

ข้อแตกต่างอีกประการหนึ่งคือไลบรารีของไคลเอ็นต์ Resource Manager จะแสดงผลออบเจ็กต์นโยบายการอนุญาตที่ใช้สัญลักษณ์แอตทริบิวต์จุด ในขณะที่ไลบรารีไคลเอ็นต์ระดับล่างจะแสดงพจนานุกรม Python ที่ใช้วงเล็บเหลี่ยม ( [ ]) เช่น ใช้ binding.role สำหรับไลบรารีไคลเอ็นต์ของ Resource Manager ส่วน binding['role'] สำหรับไลบรารีระดับล่าง บัญชีแรกยังใช้ "underscore_ eCPM" ด้วย เทียบกับไลบรารีระดับล่างที่ชอบ "CamelCased" รวมทั้งวิธีส่งในพารามิเตอร์ของ API ที่ต่างออกไปเล็กน้อย

ความแตกต่างในการใช้งานมีดังนี้

ก่อนหน้า:

allow_policy = rm_client.get_iam_policy(resource='projects/%s' % PROJ_ID)
for b in allow_policy.bindings:     # bindings in IAM allow-policy
    if b.role in _TARGETS:          # only look at GAE admin roles
        admins.update(user.split(':', 1).pop() for user in b.members)

หลัง:

allow_policy = rm_client.projects().getIamPolicy(resource=PROJ_ID).execute()
for b in allow_policy['bindings']:  # bindings in IAM allow-policy
    if b['role'] in _TARGETS:       # only look at GAE admin roles
        admins.update(user.split(':', 1).pop() for user in b['members'])

เมื่อนำการเปลี่ยนแปลงทั้งหมดนี้มารวมกัน ให้แทนที่ Python 3 _get_gae_admins() ด้วย Python 2 เวอร์ชันที่เทียบเท่านี้

def _get_gae_admins():
    'return set of App Engine admins'
    # setup constants for calling Cloud Resource Manager API
    CREDS, PROJ_ID = default(  # Application Default Credentials and project ID
            ['https://www.googleapis.com/auth/cloud-platform'])
    rm_client = discovery.build('cloudresourcemanager', 'v1', credentials=CREDS)
    _TARGETS = frozenset((     # App Engine admin roles
            'roles/viewer',
            'roles/editor',
            'roles/owner',
            'roles/appengine.appAdmin',
    ))

    # collate users who are members of at least one GAE admin role (_TARGETS)
    admins = set()                      # set of all App Engine admins
    allow_policy = rm_client.projects().getIamPolicy(resource=PROJ_ID).execute()
    for b in allow_policy['bindings']:  # bindings in IAM allow-policy
        if b['role'] in _TARGETS:       # only look at GAE admin roles
            admins.update(user.split(':', 1).pop() for user in b['members'])
    return admins

คุณไม่ต้องอัปเดตฟังก์ชัน is_admin() เนื่องจากต้องใช้ _get_gae_admins() ซึ่งได้รับการอัปเดตแล้ว

นี่เป็นการสรุปการเปลี่ยนแปลงที่จำเป็นสำหรับการพอร์ตแอป Python 3 Module 21 ไปยัง Python 2 ขอแสดงความยินดีสำหรับการเข้าถึงแอปตัวอย่างโมดูล 21 ที่อัปเดตแล้ว คุณสามารถดูโค้ดทั้งหมดได้ในโฟลเดอร์ที่เก็บโมดูล 21a

7. สรุป/ล้างข้อมูล

ขั้นตอนสุดท้ายใน Codelab คือการตรวจสอบว่าผู้ใช้หลัก (ผู้ใช้หรือบัญชีบริการ) ที่เรียกใช้แอปนี้มีสิทธิ์ที่เหมาะสมในการดำเนินการดังกล่าว จากนั้นทำให้แอปใช้งานได้เพื่อยืนยันว่าแอปทำงานได้ตามที่ต้องการและการเปลี่ยนแปลงจะแสดงในเอาต์พุต

ความสามารถในการอ่านอนุญาตนโยบาย IAM

ก่อนหน้านี้ เราได้แนะนำให้คุณรู้จักบทบาท 4 บทบาทที่จำเป็นต่อการได้รับการจดจำว่าเป็นผู้ใช้ที่ดูแลระบบ App Engine แต่ตอนนี้มีบทบาทที่ 5 ที่จะสร้างความคุ้นเคยกับบทบาทเหล่านี้

  • roles/viewer
  • roles/editor
  • roles/owner
  • roles/appengine.appAdmin
  • roles/resourcemanager.projectIamAdmin (สำหรับผู้ใช้หลักที่มีสิทธิ์เข้าถึงนโยบายการอนุญาต IAM)

บทบาท roles/resourcemanager.projectIamAdmin ช่วยให้ผู้ใช้หลักสามารถระบุได้ว่าผู้ใช้ปลายทางเป็นสมาชิกของบทบาทผู้ดูแลระบบ App Engine หรือไม่ หากไม่ได้เป็นสมาชิกใน roles/resourcemanager.projectIamAdmin การเรียกใช้ Cloud Resource Manager API เพื่อรับนโยบายการอนุญาตจะไม่สำเร็จ

คุณไม่ต้องดำเนินการใดๆ โดยชัดแจ้งที่นี่เนื่องจากแอปจะทำงานภายใต้บัญชีบริการเริ่มต้นของ App Engine ซึ่งได้รับสิทธิ์การเป็นสมาชิกในบทบาทนี้โดยอัตโนมัติ แม้ว่าคุณจะใช้บัญชีบริการเริ่มต้นในช่วงการพัฒนา เราขอแนะนำให้สร้างและใช้บัญชีบริการที่จัดการโดยผู้ใช้โดยมีสิทธิ์ที่จำเป็นน้อยที่สุดเพื่อให้แอปทำงานได้อย่างถูกต้อง หากต้องการมอบการเป็นสมาชิกให้กับบัญชีบริการดังกล่าว ให้เรียกใช้คำสั่งต่อไปนี้

$ gcloud projects add-iam-policy-binding PROJ_ID --member="serviceAccount:USR_MGD_SVC_ACCT@PROJ_ID.iam.gserviceaccount.com" --role=roles/resourcemanager.projectIamAdmin

PROJ_ID คือรหัสโปรเจ็กต์ที่อยู่ในระบบคลาวด์ และ USR_MGD_SVC_ACCT@PROJ_ID.iam.gserviceaccount.com คือบัญชีบริการที่จัดการโดยผู้ใช้ซึ่งคุณสร้างขึ้นสำหรับแอป คำสั่งนี้จะแสดงนโยบาย IAM ที่อัปเดตแล้วสำหรับโปรเจ็กต์ของคุณ ซึ่งคุณสามารถยืนยันว่าบัญชีบริการมีการเป็นสมาชิกใน roles/resourcemanager.projectIamAdmin ดูข้อมูลเพิ่มเติมได้ในเอกสารอ้างอิง หากต้องการทำซ้ำ คุณไม่จำเป็นต้องออกคำสั่งนั้นใน Codelab นี้ แต่ให้บันทึกเป็นข้อมูลอ้างอิงสำหรับการปรับแอปให้ทันสมัย

ติดตั้งใช้งานและยืนยันแอปพลิเคชัน

อัปโหลดแอปไปยังระบบคลาวด์ด้วยคำสั่ง gcloud app deploy มาตรฐาน เมื่อทำให้ใช้งานได้แล้ว คุณควรเห็นฟังก์ชันการทำงานเกือบเหมือนกับแอปโมดูล 20 เว้นแต่ว่าคุณได้แทนที่บริการผู้ใช้ App Engine ด้วย Cloud Identity Platform (และ Firebase Auth) สำหรับการจัดการผู้ใช้เรียบร้อยแล้ว

3a83ae745121d70.png

ความแตกต่างอย่างหนึ่งที่คุณจะสังเกตเห็นเมื่อเทียบกับโมดูล 20 คือ การคลิกที่ผลการเข้าสู่ระบบในป๊อปอัปแทนการเปลี่ยนเส้นทาง ซึ่งจับภาพไว้ในภาพหน้าจอด้านล่างบางส่วน อย่างไรก็ตาม เช่นเดียวกับโมดูล 20 ลักษณะการทำงานจะแตกต่างกันเล็กน้อย โดยขึ้นอยู่กับจำนวนบัญชี Google ที่ลงทะเบียนไว้กับเบราว์เซอร์

หากไม่มีผู้ใช้ที่ลงทะเบียนกับเบราว์เซอร์หรือผู้ใช้รายเดียวที่ยังไม่ได้ลงชื่อเข้าใช้ ป๊อปอัป Google Sign-In ทั่วไปจะปรากฏขึ้น

8437f5f3d489a942.png

หากมีผู้ใช้รายหนึ่งลงทะเบียนกับเบราว์เซอร์ของคุณ แต่ลงชื่อเข้าใช้ที่อื่น จะไม่มีกล่องโต้ตอบปรากฏขึ้น (หรือกล่องโต้ตอบปรากฏขึ้นและปิดทันที) และแอปจะอยู่ในสถานะลงชื่อเข้าใช้ (แสดงอีเมลของผู้ใช้และปุ่มออกจากระบบ)

นักพัฒนาแอปบางรายอาจต้องการให้บริการเครื่องมือเลือกบัญชี แม้จะเป็นผู้ใช้รายเดียวก็ตาม โดยทำดังนี้

b75624cb68d94557.png

หากต้องการนํามาใช้ ให้ยกเลิกการทําหมายเหตุบรรทัด provider.setCustomParameters({prompt: 'select_account'}); ในเทมเพลตเว็บตามที่อธิบายไว้ก่อนหน้านี้

หากมีผู้ใช้หลายคน กล่องโต้ตอบเครื่องมือเลือกบัญชีจะปรากฏขึ้น (ดูด้านล่าง) ผู้ใช้จะได้รับข้อความแจ้งหากยังไม่ได้ลงชื่อเข้าใช้ หากลงชื่อเข้าใช้อยู่แล้ว ป๊อปอัปจะหายไปและแอปจะเข้าสู่สถานะลงชื่อเข้าใช้

c454455b6020d5e4.png

สถานะการลงชื่อเข้าใช้ของโมดูล 21 มีลักษณะเหมือนกับอินเทอร์เฟซผู้ใช้ของโมดูล 20:

49ebe4dcc1eff11f.png

เช่นเดียวกันกับกรณีที่ผู้ใช้ที่ดูแลระบบได้ลงชื่อเข้าใช้

44302f35b39856eb.png

โมดูล 20 จะเข้าถึงตรรกะสำหรับเนื้อหาเทมเพลตเว็บจากแอป (โค้ดฝั่งเซิร์ฟเวอร์) ซึ่งต่างจากโมดูล 21 ข้อบกพร่องของโมดูล 20 คือจะมีการลงทะเบียนการเข้าชม 1 ครั้งเมื่อผู้ใช้ปลายทางไปยังแอปเป็นครั้งแรก และอีกการเข้าชมหนึ่งจะลงทะเบียนเมื่อผู้ใช้ลงชื่อเข้าใช้

สำหรับโมดูล 21 ตรรกะการเข้าสู่ระบบจะเกิดขึ้นในเทมเพลตเว็บเท่านั้น (โค้ดฝั่งไคลเอ็นต์) โดยที่ไม่จำเป็นต้องเดินทางฝั่งเซิร์ฟเวอร์เพื่อระบุเนื้อหาที่จะแสดง การเรียกไปยังเซิร์ฟเวอร์เพียงอย่างเดียวคือการตรวจสอบผู้ใช้ที่ดูแลระบบหลังจากที่ผู้ใช้ปลายทางลงชื่อเข้าใช้ ซึ่งหมายความว่าการเข้าสู่ระบบและการออกจากระบบจะไม่บันทึกการเข้าชมเพิ่มเติม ดังนั้นรายการการเข้าชมล่าสุดจะมีค่าคงที่สำหรับการดำเนินการจัดการผู้ใช้ โปรดสังเกตว่าภาพหน้าจอด้านบนแสดงการเข้าชม 4 ครั้งชุดเดียวกันในการเข้าสู่ระบบผู้ใช้หลายราย

ภาพหน้าจอโมดูล 20 แสดง "ข้อบกพร่องการเข้าชมซ้ำ" ที่จุดเริ่มต้นของ Codelab นี้ บันทึกการเข้าชมแยกกันจะปรากฏสำหรับแต่ละการดำเนินการลงชื่อเข้าใช้หรือออกจากระบบ ตรวจสอบการประทับเวลาการเข้าชมครั้งล่าสุดสำหรับภาพหน้าจอแต่ละภาพที่แสดงการจัดเรียงตามลำดับเวลา

ล้างข้อมูล

ทั่วไป

หากดำเนินการเสร็จแล้ว เราขอแนะนำให้คุณปิดใช้แอป App Engine เพื่อหลีกเลี่ยงการเรียกเก็บเงิน อย่างไรก็ตาม หากคุณต้องการทดสอบหรือทดลองเพิ่มเติม แพลตฟอร์ม App Engine จะมีโควต้าฟรี และตราบใดที่คุณใช้งานไม่เกินระดับการใช้งานดังกล่าว เราก็จะไม่เรียกเก็บเงิน ค่าดังกล่าวมีไว้สําหรับการประมวลผล แต่ก็อาจมีการเรียกเก็บเงินค่าบริการ App Engine ที่เกี่ยวข้องด้วย ดังนั้นโปรดดูข้อมูลเพิ่มเติมในหน้าราคา หากการย้ายข้อมูลนี้เกี่ยวข้องกับบริการระบบคลาวด์อื่นๆ ระบบจะเรียกเก็บเงินแยกต่างหาก ในทั้ง 2 กรณี หากมี โปรดดูส่วน "เฉพาะสำหรับ Codelab นี้" ด้านล่าง

เพื่อการเปิดเผยข้อมูลทั้งหมด การทำให้ใช้งานได้กับแพลตฟอร์มการประมวลผลแบบ Serverless ของ Google Cloud อย่าง App Engine จะมีค่าใช้จ่ายในการสร้างและพื้นที่เก็บข้อมูลเล็กน้อย Cloud Build มีโควต้าฟรีของตนเอง เช่นเดียวกับ Cloud Storage พื้นที่เก็บข้อมูลของรูปภาพจะใช้โควต้านั้นหมด อย่างไรก็ตาม คุณอาจอาศัยอยู่ในภูมิภาคที่ไม่มีรุ่นฟรีดังกล่าว โปรดระวังการใช้พื้นที่เก็บข้อมูลของคุณเพื่อลดค่าใช้จ่ายที่อาจเกิดขึ้น "โฟลเดอร์" เฉพาะของ Cloud Storage ที่คุณควรตรวจสอบมีดังนี้

  • console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/images
  • console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
  • ลิงก์พื้นที่เก็บข้อมูลด้านบนขึ้นอยู่กับPROJECT_IDและLOC เช่น "us" หากแอปของคุณโฮสต์ในสหรัฐอเมริกา

ในทางกลับกัน หากคุณไม่ต้องการดำเนินการกับแอปพลิเคชันนี้หรือ Codelab การย้ายข้อมูลอื่นๆ ที่เกี่ยวข้องต่อไป และต้องการลบทุกอย่างออกทั้งหมด ให้ปิดโปรเจ็กต์

เฉพาะสำหรับ Codelab นี้

บริการในรายการด้านล่างเป็นบริการเฉพาะสำหรับ Codelab นี้ โปรดดูข้อมูลเพิ่มเติมในเอกสารประกอบของผลิตภัณฑ์แต่ละรายการ

  • บริการ App Engine Datastore ให้บริการโดย Cloud Datastore (Cloud Firestore ในโหมด Datastore) ซึ่งมีรุ่นฟรีเช่นกัน ดูข้อมูลเพิ่มเติมได้ที่หน้าราคา
  • การใช้ Cloud Identity Platform อาจมีความ “ฟรี” ในระดับหนึ่ง โดยขึ้นอยู่กับบริการที่คุณใช้ ดูรายละเอียดเพิ่มเติมในหน้าราคา
  • ส่วนใหญ่แล้ว คุณสามารถใช้ Cloud Resource Manager API ได้ฟรีตามหน้าราคา

ขั้นตอนถัดไป

นอกเหนือจากบทแนะนำนี้ โมดูลการย้ายข้อมูลอื่นๆ ที่มุ่งเน้นการย้ายจากบริการพร้อมแพ็กเกจแบบเดิมที่จะพิจารณามีดังนี้

  • โมดูล 2: ย้ายข้อมูลจาก App Engine ndb ไปยัง Cloud NDB
  • โมดูล 7-9: ย้ายข้อมูลจากคิวงานของ App Engine (งานแบบพุช) ไปยัง Cloud Tasks
  • โมดูล 12-13: ย้ายข้อมูลจาก App Engine Memcache ไปยัง Cloud Memorystore
  • โมดูล 15-16: ย้ายข้อมูลจาก App Engine Blobstore ไปยัง Cloud Storage
  • โมดูล 18-19: ย้ายข้อมูลจากคิวงานของ App Engine (พุลงาน) ไปยัง Cloud Pub/Sub

App Engine ไม่ใช่แพลตฟอร์มแบบ Serverless เพียงแพลตฟอร์มเดียวใน Google Cloud อีกต่อไป หากคุณมีแอป App Engine ขนาดเล็กหรือแอปที่มีฟังก์ชันการทำงานที่จำกัดและต้องการเปลี่ยนเป็น Microservice แบบสแตนด์อโลน หรือต้องการแตกแอปโมโนลิธให้เป็นคอมโพเนนต์ที่ใช้ซ้ำได้หลายรายการ เหตุผลที่ดีเหล่านี้ควรพิจารณาเปลี่ยนไปใช้ Cloud Functions หากการขนส่งด้วยคอนเทนเนอร์เป็นส่วนหนึ่งของเวิร์กโฟลว์การพัฒนาแอปพลิเคชัน โดยเฉพาะอย่างยิ่งหากประกอบด้วยไปป์ไลน์ CI/CD (การรวมอย่างต่อเนื่อง/การส่งมอบหรือการติดตั้งใช้งานอย่างต่อเนื่อง) ให้ลองย้ายข้อมูลไปยัง Cloud Run สถานการณ์เหล่านี้ครอบคลุมในโมดูลต่อไปนี้

  • ย้ายข้อมูลจาก App Engine ไปยัง Cloud Functions: ดูโมดูล 11
  • ย้ายข้อมูลจาก App Engine ไปยัง Cloud Run: ดูโมดูล 4 เพื่อสร้างคอนเทนเนอร์แอปด้วย Docker หรือโมดูล 5 เพื่อดำเนินการดังกล่าวโดยไม่ต้องมีคอนเทนเนอร์ ไม่มีความรู้เกี่ยวกับ Docker หรือDockerfile

คุณจะเปลี่ยนไปใช้แพลตฟอร์มแบบ Serverless อื่นหรือไม่ก็ได้ และเราขอแนะนำให้พิจารณาตัวเลือกที่ดีที่สุดสำหรับแอปและ Use Case ของคุณก่อนทำการเปลี่ยนแปลงใดๆ

ไม่ว่าคุณจะพิจารณาโมดูลการย้ายข้อมูลใดในครั้งถัดไป คุณสามารถเข้าถึงเนื้อหาของสถานีย้ายข้อมูลแบบ Serverless (โค้ดแล็บ วิดีโอ ซอร์สโค้ด [เมื่อพร้อมให้บริการ]) ทั้งหมดได้ที่ที่เก็บโอเพนซอร์ส README ของที่เก็บยังให้คำแนะนำเกี่ยวกับการย้ายข้อมูลที่ควรพิจารณาและ "คำสั่ง" ที่เกี่ยวข้อง โมดูลการย้ายข้อมูล

8. แหล่งข้อมูลเพิ่มเติม

รายการด้านล่างนี้คือแหล่งข้อมูลเพิ่มเติมสําหรับนักพัฒนาแอปที่สำรวจโมดูลการย้ายข้อมูลนี้หรือโมดูลที่เกี่ยวข้องเพิ่มเติม คุณสามารถแสดงความคิดเห็นเกี่ยวกับเนื้อหานี้ ดูลิงก์ไปยังโค้ด และเอกสารประกอบต่างๆ ที่อาจเป็นประโยชน์ได้ที่ด้านล่าง

ปัญหา/ความคิดเห็นของ Codelab

หากมีปัญหาใดๆ เกี่ยวกับ Codelab นี้ โปรดค้นหาปัญหาของคุณก่อนยื่น ลิงก์สำหรับค้นหาและสร้างปัญหาใหม่

ทรัพยากรการย้ายข้อมูล

คุณสามารถดูลิงก์ไปยังโฟลเดอร์ที่เก็บสำหรับโมดูล 20 (START) และโมดูล 21 (FINISH) ได้ในตารางด้านล่าง

Codelab

Python 2

Python 3

โมดูล 20

รหัส

(ไม่มี)

โมดูล 21 (Codelab นี้)

รหัส

รหัส

ข้อมูลอ้างอิงออนไลน์

ด้านล่างนี้คือแหล่งข้อมูลที่เกี่ยวข้องกับบทแนะนำนี้

Cloud Identity Platform และ Cloud Marketplace

Cloud Resource Manager, Cloud IAM, Firebase Admin SDK

ผู้ใช้ App Engine, App Engine NDB, Cloud NDB, Cloud Datastore

การอ้างอิงโมดูลการย้ายข้อมูลอื่นๆ

การย้ายข้อมูล App Engine

แพลตฟอร์ม App Engine

Cloud SDK

ข้อมูลอื่นๆ เกี่ยวกับระบบคลาวด์

วิดีโอ

ใบอนุญาต

ผลงานนี้ได้รับอนุญาตภายใต้ใบอนุญาตทั่วไปครีเอทีฟคอมมอนส์แบบระบุแหล่งที่มา 2.0