1. Tổng quan
Loạt lớp học lập trình về Trạm di chuyển không máy chủ (hướng dẫn thực hành theo tiến độ riêng) và video có liên quan nhằm giúp các nhà phát triển Google Cloud không máy chủ không hiện đại hoá các ứng dụng của họ bằng cách hướng dẫn họ thực hiện một hoặc nhiều quá trình di chuyển, chủ yếu là ngừng sử dụng các dịch vụ cũ. Việc này giúp ứng dụng của bạn dễ di chuyển hơn, đồng thời mang đến cho bạn nhiều lựa chọn và độ linh hoạt hơn, cho phép bạn tích hợp và truy cập vào nhiều sản phẩm của Cloud hơn, đồng thời dễ dàng nâng cấp lên bản phát hành ngôn ngữ mới hơn. Mặc dù ban đầu tập trung vào những người dùng Cloud sớm nhất, chủ yếu là các nhà phát triển App Engine (môi trường tiêu chuẩn), nhưng loạt bài này đủ rộng để bao gồm các nền tảng không máy chủ khác như Cloud Functions và Cloud Run hoặc ở những nơi khác nếu có.
Mục đích của lớp học lập trình này là hướng dẫn các nhà phát triển App Engine sử dụng Python 2 cách di chuyển từ dịch vụ/API người dùng App Engine sang Cloud Identity Platform (GCIP). Ngoài ra còn có quá trình di chuyển ngầm từ App Engine NDB sang Cloud NDB để truy cập Datastore (chủ yếu được đề cập trong Mô-đun di chuyển 2) cũng như nâng cấp lên Python 3.
Mô-đun 20 trình bày cách thêm việc sử dụng API Người dùng vào ứng dụng mẫu của Mô-đun 1. Trong học phần này, bạn sẽ sử dụng ứng dụng hoàn chỉnh của Mô-đun 20 và di chuyển mức sử dụng ứng dụng đó sang Cloud Identity Platform.
Bạn sẽ tìm hiểu cách
- Thay thế việc sử dụng dịch vụ Người dùng App Engine bằng Nền tảng Cloud Identity
- Thay thế việc sử dụng App Engine NDB bằng Cloud NDB (xem thêm Mô-đun 2)
- Thiết lập nhiều nhà cung cấp danh tính để xác thực bằng tính năng Xác thực Firebase
- Sử dụng Cloud Resource Manager API để lấy thông tin IAM của dự án
- Sử dụng SDK quản trị của Firebase để nhận thông tin người dùng
- Chuyển ứng dụng mẫu sang Python 3
Bạn cần có
- Một dự án Google Cloud Platform có tài khoản thanh toán GCP đang hoạt động
- Kỹ năng Python cơ bản
- Kiến thức thực hành về các lệnh Linux phổ biến
- Kiến thức cơ bản về việc phát triển và triển khai ứng dụng App Engine
- Một ứng dụng mẫu của App Engine 20 đang hoạt động
Khảo sát
Bạn sẽ sử dụng hướng dẫn này như thế nào?
Bạn đánh giá thế nào về trải nghiệm sử dụng Python?
Bạn đánh giá thế nào về trải nghiệm sử dụng các dịch vụ của Google Cloud?
2. Thông tin khái quát
Dịch vụ người dùng App Engine là hệ thống xác thực người dùng để các ứng dụng App Engine sử dụng. Dịch vụ này cung cấp tính năng Đăng nhập bằng Google làm nhà cung cấp danh tính, cung cấp đường liên kết đăng nhập và đăng xuất thuận tiện để sử dụng trong ứng dụng, đồng thời hỗ trợ khái niệm người dùng quản trị và chức năng chỉ dành cho quản trị viên. Để cải thiện khả năng di chuyển của ứng dụng, bạn nên chuyển từ các dịch vụ đi kèm của App Engine cũ sang các dịch vụ độc lập trên Cloud, chẳng hạn như từ dịch vụ Người dùng sang Cloud Identity Platform và nhiều dịch vụ khác.
Nền tảng danh tính dựa trên tính năng Xác thực Firebase và bổ sung một số tính năng dành cho doanh nghiệp như xác thực đa yếu tố, OIDC (OpenID Connect) và Hỗ trợ đăng nhập một lần (SSO) dựa trên SAML, nhiều khách hàng thuê, đạt 99, 95% theo thoả thuận mức độ cung cấp dịch vụ (SLA) và nhiều lợi ích khác. Những khác biệt này cũng được làm nổi bật trên trang so sánh sản phẩm Xác thực Firebase và Nền tảng nhận dạng. Cả hai sản phẩm đều có nhiều tính năng hơn đáng kể so với chức năng do dịch vụ Người dùng cung cấp.
Lớp học lập trình Mô-đun 21 này minh hoạ việc chuyển đổi phương thức xác thực người dùng của ứng dụng từ Dịch vụ người dùng sang các tính năng Nền tảng nhận dạng mà phản ánh gần nhất chức năng được minh hoạ trong Mô-đun 20. Mô-đun 21 cũng trình bày việc di chuyển từ App Engine NDB sang Cloud NDB để truy cập vào Datastore, lặp lại quá trình di chuyển Mô-đun 2.
Mặc dù mã Mô-đun 20 là "được quảng cáo" dưới dạng ứng dụng mẫu Python 2, bản thân nguồn tương thích với Python 2 và 3, và nó vẫn như vậy ngay cả sau khi chuyển sang Identity Platform (và Cloud NDB) ở đây trong Mô-đun 21. Bạn có thể tiếp tục sử dụng dịch vụ Người dùng trong khi nâng cấp lên Python 3 vì việc di chuyển sang Nền tảng nhận dạng là không bắt buộc. Xem và video Lớp học lập trình về Mô-đun 17 để tìm hiểu cách tiếp tục sử dụng các dịch vụ đi kèm trong khi nâng cấp lên môi trường thời gian chạy thế hệ thứ 2 như Python 3.
Hướng dẫn này bao gồm các bước sau:
- Thiết lập/Chuẩn bị
- Cập nhật cấu hình
- Sửa đổi mã xử lý ứng dụng
3. Thiết lập/Chuẩn bị
Phần này giải thích cách:
- Thiết lập dự án trên Cloud
- Tải ứng dụng mẫu cơ sở
- (Triển khai lại) và xác thực ứng dụng cơ sở
- Bật các API/dịch vụ Google Cloud mới
Các bước này giúp đảm bảo bạn đang bắt đầu với đoạn mã đang hoạt động, đã sẵn sàng để di chuyển sang các dịch vụ Cloud độc lập.
1. Thiết lập dự án
Nếu bạn đã hoàn thành lớp học lập trình Mô-đun 20, hãy sử dụng lại chính dự án (và mã) đó. Ngoài ra, hãy tạo một dự án hoàn toàn mới hoặc sử dụng lại một dự án hiện có khác. Hãy đảm bảo dự án này có một tài khoản thanh toán đang hoạt động và có một ứng dụng App Engine đã bật. Tìm mã dự án của bạn để sử dụng trong lớp học lập trình này và sử dụng mã này bất cứ khi nào bạn gặp biến PROJ_ID
.
2. Tải ứng dụng mẫu cơ sở
Một trong những điều kiện tiên quyết là ứng dụng App Engine Mô-đun 20 đang hoạt động, vì vậy, hãy hoàn thành lớp học lập trình của ứng dụng (đề xuất; đường liên kết ở trên) hoặc sao chép mã Mô-đun 20 từ kho lưu trữ. Cho dù bạn sử dụng tài khoản của bạn hay của chúng tôi, đây là nơi chúng tôi sẽ bắt đầu ("START"). Lớp học lập trình này sẽ hướng dẫn bạn thực hiện quá trình di chuyển, kết thúc bằng mã tương tự như những gì trong thư mục kho lưu trữ Mô-đun 21 ("Finish").
- START: Thư mục mô-đun 20 (Python 2)
- HOÀN TẤT: Thư mục Mô-đun 21 ( Python 2 hoặc Python 3)
- Toàn bộ kho lưu trữ (để sao chép hoặc tải tệp ZIP xuống)
Sao chép thư mục kho lưu trữ Mô-đun 20. Kết quả này sẽ có dạng như dưới đây và có thể có thư mục lib
nếu bạn thực hiện lớp học lập trình Mô-đun 20:
$ ls README.md appengine_config.py templates app.yaml main.py requirements.txt
3. (Triển khai lại) và xác thực ứng dụng cơ sở
Thực thi các bước sau để triển khai ứng dụng Mô-đun 20:
- Xoá thư mục
lib
(nếu có) rồi chạypip install -t lib -r requirements.txt
để điền lại thư mục đó. Có thể bạn sẽ phải sử dụngpip2
nếu đã cài đặt cả Python 2 và 3. - Hãy đảm bảo bạn đã cài đặt và khởi chạy công cụ dòng lệnh
gcloud
, đồng thời xem lại việc sử dụng công cụ này. - Nếu bạn không muốn nhập
PROJ_ID
với mỗi lệnhgcloud
được đưa ra, trước tiên, hãy thiết lập dự án trên đám mây vớigcloud config set project
PROJ_ID
. - Triển khai ứng dụng mẫu bằng
gcloud app deploy
- Kiểm tra để đảm bảo ứng dụng chạy như mong đợi mà không gặp lỗi. Nếu bạn đã hoàn thành lớp học lập trình Mô-đun 20, ứng dụng sẽ hiển thị thông tin đăng nhập của người dùng (email của người dùng, có thể là "huy hiệu quản trị viên" và nút đăng nhập/đăng xuất) ở trên cùng cùng với những lượt truy cập gần đây nhất (minh hoạ bên dưới).
Việc đăng nhập với tư cách là người dùng thông thường sẽ làm cho địa chỉ email của người dùng hiển thị, còn nút "Đăng nhập" nút chuyển thành "Đăng xuất" nút:
Khi đăng nhập với tư cách là người dùng quản trị, địa chỉ email của người dùng đó sẽ xuất hiện cùng với "(quản trị viên)" bên cạnh bài đăng đó:
4. Bật API/dịch vụ Google Cloud mới
Giới thiệu
Ứng dụng Mô-đun 20 sử dụng API Người dùng và NDB của App Engine, các dịch vụ đi kèm không yêu cầu thiết lập bổ sung, nhưng các dịch vụ đám mây độc lập thì có. Ứng dụng được cập nhật sẽ sử dụng cả Cloud Identity Platform và Kho dữ liệu đám mây (thông qua thư viện ứng dụng Cloud NDB). Ngoài ra, nhu cầu xác định người dùng quản trị của App Engine cũng yêu cầu sử dụng Cloud Resource Manager API.
Chi phí
- App Engine và Cloud Datastore có "Luôn miễn phí" và miễn là bạn không phải trả các giới hạn đó, bạn sẽ không phải chịu phí khi hoàn thành hướng dẫn này. Ngoài ra, hãy xem trang giá của App Engine và trang giá của Cloud Datastore để biết thêm chi tiết.
- Việc sử dụng Cloud Identity Platform sẽ được tính phí tuỳ thuộc vào số lượng người dùng hoạt động hằng tháng (MAU) hoặc số lượt xác thực; một số phiên bản của "miễn phí" có sẵn cho từng mô hình sử dụng. Hãy xem trang giá để biết thêm chi tiết. Ngoài ra, mặc dù App Engine và Cloud Datastore đều yêu cầu thanh toán, nhưng việc sử dụng GCIP là không bắt buộc phải bật tính năng thanh toán, miễn là bạn không vượt quá hạn mức hằng ngày không dùng công cụ. Vì vậy, hãy cân nhắc việc này đối với những dự án Cloud không liên quan đến Cloud API/dịch vụ yêu cầu thanh toán.
- Bạn có thể sử dụng miễn phí Cloud Resource Manager API đối với hầu hết các phần trên trang giá của dịch vụ này.
Người dùng bật Cloud API từ bảng điều khiển Cloud hoặc từ dòng lệnh (thông qua lệnh gcloud
, một phần của SDK đám mây), tuỳ thuộc vào lựa chọn ưu tiên của bạn. Hãy bắt đầu với Cloud Datastore và Cloud Resource Manager API.
Trên Cloud Console
Truy cập vào trang Thư viện của Trình quản lý API (để tìm đúng dự án) trong Cloud Console và tìm một API bằng thanh tìm kiếm.
Bật các API này:
Tìm và nhấp vào nút Bật cho từng API riêng biệt – bạn có thể được nhắc cung cấp thông tin thanh toán. Ví dụ: đây là trang cho Resource Manager API (API Trình quản lý tài nguyên):
Nút này sẽ chuyển thành Quản lý khi được bật (thường sau vài giây):
Bật Cloud Datastore theo cách tương tự:
Từ dòng lệnh
Mặc dù thông tin trực quan để bật các API từ bảng điều khiển, một số người lại thích dòng lệnh hơn. Không chỉ vậy, bạn còn có thể bật nhiều API cùng một lúc. Phát lệnh này để bật cả API Cloud Datastore lẫn Cloud Resource Manager rồi chờ thao tác hoàn tất, như minh hoạ dưới đây:
$ gcloud services enable cloudresourcemanager.googleapis.com datastore.googleapis.com Operation "operations/acat.p2-aaa-bbb-ccc-ddd-eee-ffffff" finished successfully.
Bạn có thể được nhắc cung cấp thông tin thanh toán.
Các "URL" đối với mỗi API dùng trong lệnh trên được gọi là tên dịch vụ API. Bạn có thể tìm thấy các tên này ở cuối trang thư viện cho từng API. Nếu muốn bật các Cloud API khác cho ứng dụng của mình, bạn có thể tìm tên dịch vụ tương ứng trên trang API tương ứng. Lệnh này liệt kê tất cả tên dịch vụ của những API mà bạn có thể bật:
gcloud services list
--available --filter="name:googleapis.com"
.
Bất kể là trong bảng điều khiển Cloud hay trên dòng lệnh, sau khi bạn hoàn tất các bước trên, giờ đây, mẫu của chúng tôi sẽ có thể truy cập vào các API đó. Các bước tiếp theo là bật Cloud Identity Platform và thay đổi mã cần thiết.
Bật và thiết lập Cloud Identity Platform (chỉ bảng điều khiển Cloud)
Cloud Identity Platform là một dịch vụ trên Marketplace vì dịch vụ này kết nối hoặc phụ thuộc vào một tài nguyên bên ngoài Google Cloud, ví dụ: dịch vụ Xác thực Firebase. Hiện tại, bạn chỉ có thể bật các dịch vụ của Marketplace trên bảng điều khiển Cloud. Hãy làm theo các bước sau:
- Truy cập vào trang Cloud Identity Platform trong Cloud Marketplace rồi nhấp vào nút Bật ở đó. Nâng cấp từ tính năng Xác thực Firebase nếu được nhắc. Làm như vậy sẽ mở khoá các tính năng bổ sung, chẳng hạn như các tính năng được mô tả trước đó trong phần Nền. Dưới đây là trang Thị trường, trong đó có nút Bật được làm nổi bật:
- Sau khi bật Nền tảng danh tính, có thể bạn sẽ tự động được đưa đến trang Nhà cung cấp danh tính. Nếu chưa, hãy sử dụng đường liên kết thuận tiện này để truy cập vào trang đó.
- Bật nhà cung cấp dịch vụ Xác thực của Google. Nếu chưa thiết lập nhà cung cấp nào, hãy nhấp vào Thêm nhà cung cấp rồi chọn Google. Khi quay lại màn hình này, mục Google sẽ được bật. Google là nhà cung cấp dịch vụ xác thực duy nhất mà chúng tôi sử dụng trong hướng dẫn này để phản ánh dịch vụ Người dùng App Engine dưới dạng một dịch vụ Đăng nhập bằng Google gọn nhẹ. Trong các ứng dụng của riêng mình, bạn có thể bật các nhà cung cấp dịch vụ xác thực khác.
- Khi bạn đã chọn và thiết lập Google và các nhà cung cấp dịch vụ xác thực mà bạn muốn khác, hãy nhấp vào Chi tiết thiết lập ứng dụng. Trong cửa sổ hộp thoại đảm bảo, hãy sao chép
apiKey
vàauthDomain
trong đối tượngconfig
trên thẻ Web, lưu cả hai ở nơi an toàn. Tại sao không sao chép toàn bộ? Đoạn mã trong hộp thoại này được cố định giá trị trong mã và ghi ngày tháng, vì vậy, chỉ cần lưu các bit quan trọng nhất và sử dụng chúng trong mã của chúng tôi với mức sử dụng Xác thực Firebase đồng thời hơn. Sau khi bạn sao chép các giá trị và lưu chúng ở nơi an toàn, hãy nhấp vào nút Đóng, hoàn tất tất cả các bước thiết lập cần thiết.
4. Cập nhật cấu hình
Các cập nhật về cấu hình bao gồm thay đổi nhiều tệp cấu hình cũng như tạo phiên bản tương đương của App Engine nhưng trong hệ sinh thái Cloud Identity Platform.
appengine_config.py
- Nếu nâng cấp lên Python 3, hãy xoá
appengine_config.py
- Nếu bạn có kế hoạch hiện đại hoá thành Identity Platform (Nền tảng nhận dạng) nhưng vẫn sử dụng Python 2, vui lòng không xoá tệp này. Thay vào đó, chúng tôi sẽ cập nhật mã này sau trong quá trình điều chỉnh cho phiên bản cũ của Python 2.
requirements.txt
Tệp requirements.txt
của Mô-đun 20 chỉ được liệt kê Flask. Đối với Mô-đun 21, hãy thêm các gói sau:
Lúc này, nội dung của requirements.txt
sẽ có dạng như sau:
flask
google-auth
google-cloud-ndb
google-cloud-resource-manager
firebase-admin
app.yaml
- Nâng cấp lên Python 3 có nghĩa là đơn giản hoá tệp
app.yaml
. Xoá mọi thứ ngoại trừ lệnh thời gian chạy và đặt lệnh đó thành một phiên bản Python 3 hiện được hỗ trợ. Ví dụ này hiện sử dụng phiên bản 3.10. - Nếu vẫn tiếp tục sử dụng Python 2, bạn chưa cần làm gì cả.
TRƯỚC KHI:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
Ứng dụng mẫu Module 20 không có trình xử lý tệp tĩnh. Nếu các ứng dụng của bạn có thay đổi, hãy giữ nguyên chúng. Bạn có thể xoá tất cả trình xử lý tập lệnh của mình nếu muốn hoặc chỉ cần để chúng ở đó để tham khảo, miễn là bạn thay đổi tên người dùng của các trình xử lý đó thành auto
, như mô tả trong hướng dẫn di chuyển app.yaml
. Với những thay đổi này, app.yaml
đã cập nhật cho Python 3 được đơn giản hoá thành:
SAU KHI:
runtime: python310
Các nội dung cập nhật khác về cấu hình
Dù vẫn ở trên Python 2 hay chuyển sang Python 3, nếu bạn có thư mục lib
, hãy xoá thư mục đó.
5. Sửa đổi mã xử lý ứng dụng
Phần này giới thiệu các bản cập nhật cho tệp ứng dụng chính, main.py
, thay thế việc sử dụng dịch vụ Người dùng App Engine bằng Cloud Identity Platform. Sau khi cập nhật ứng dụng chính, bạn sẽ cập nhật mẫu dành cho web (templates/index.html
).
Cập nhật lệnh nhập và khởi chạy
Hãy làm theo các bước bên dưới để cập nhật các lệnh nhập và khởi tạo tài nguyên ứng dụng:
- Để nhập, hãy thay thế App Engine NDB bằng Cloud NDB.
- Cùng với Cloud NDB, hãy nhập cả Cloud Resource Manager (Trình quản lý tài nguyên đám mây).
- Nền tảng nhận dạng dựa trên tính năng Xác thực Firebase, vì vậy, hãy nhập SDK quản trị của Firebase.
- Cloud API đòi hỏi bạn phải dùng một ứng dụng API, vì vậy hãy khởi động ứng dụng này cho Cloud NDB ngay bên dưới khi khởi chạy Flask.
Mặc dù gói Cloud Resource Manager (Trình quản lý tài nguyên đám mây) được nhập tại đây, nhưng chúng ta sẽ sử dụng gói này ở giai đoạn sau trong quá trình khởi chạy ứng dụng. Dưới đây là các mục nhập và khởi tạo từ Mô-đun 20, theo sau là cách các phần này sẽ trông như thế nào sau khi triển khai các thay đổi ở trên:
TRƯỚC KHI:
from flask import Flask, render_template, request
from google.appengine.api import users
from google.appengine.ext import ndb
app = Flask(__name__)
SAU KHI:
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()
Dịch vụ hỗ trợ dành cho người dùng Quản trị trên App Engine
Sau đây là 2 thành phần bạn cần thêm vào ứng dụng để hỗ trợ việc nhận dạng người dùng quản trị:
_get_gae_admins()
— nhóm người dùng quản trị tổng hợp; đã gọi một lần và đã lưuis_admin()
– kiểm tra xem người dùng đã đăng nhập có phải là người dùng quản trị hay không; được gọi trên bất kỳ thông tin đăng nhập nào của người dùng
Hàm hiệu dụng _get_gae_admins()
sẽ gọi Resource Manager API (API Trình quản lý tài nguyên) để tìm nạp Cloud IAM allow-policy hiện tại. Chính sách cho phép xác định và thực thi những vai trò được cấp cho người dùng chính (người dùng là người, tài khoản dịch vụ, v.v.). Quá trình thiết lập bao gồm:
- Đang tìm nạp mã dự án trên Cloud (
PROJ_ID
) - Tạo ứng dụng API Trình quản lý tài nguyên (
rm_client
) - Tạo nhóm vai trò Quản trị viên App Engine (chỉ đọc) (
_TARGETS
)
Trình quản lý tài nguyên yêu cầu mã dự án trên Cloud, vì vậy, hãy nhập google.auth.default()
và gọi hàm đó để lấy mã dự án. Lệnh gọi đó có một tham số trông giống như một URL nhưng là phạm vi quyền của OAuth2. Khi chạy các ứng dụng trên đám mây, chẳng hạn như trên ứng dụng VM hoặc App Engine của Compute Engine, một tài khoản dịch vụ mặc định sẽ được cung cấp và có các đặc quyền rộng. Theo phương pháp hay nhất về đặc quyền tối thiểu, bạn nên tạo tài khoản dịch vụ do người dùng quản lý của riêng mình.
Đối với các lệnh gọi API, bạn nên thêm nữa giảm phạm vi ứng dụng xuống mức tối thiểu cần thiết để hoạt động đúng cách. Lệnh gọi API Trình quản lý tài nguyên mà chúng ta đang thực hiện là get_iam_policy()
cần một trong các phạm vi sau để hoạt động:
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
Ứng dụng mẫu chỉ cần quyền chỉ có thể đọc đối với chính sách cho phép. Công cụ này không sửa đổi chính sách cũng như không cần quyền truy cập vào toàn bộ dự án. Điều đó có nghĩa là ứng dụng không cần bất kỳ quyền nào trong số 3 quyền đầu tiên. Bước cuối cùng là tất cả những gì cần thiết và đó là việc chúng ta đang triển khai cho ứng dụng mẫu.
Phần nội dung chính của hàm này tạo ra một nhóm trống gồm những người dùng quản trị (admins
), tìm nạp allow_policy
qua get_iam_policy()
và lặp lại thông qua tất cả các liên kết của hàm để tìm cụ thể vai trò Quản trị viên của App Engine:
roles/viewer
roles/editor
roles/owner
roles/appengine.appAdmin
Đối với mỗi vai trò mục tiêu được tìm thấy, hệ thống sẽ tổng hợp những người dùng thuộc vai trò đó, thêm họ vào nhóm người dùng quản trị chung. Tùy chọn này kết thúc bằng cách trả về tất cả người dùng quản trị được tìm thấy và lưu vào bộ nhớ đệm dưới dạng hằng số (_ADMINS
) trong suốt thời gian hoạt động của phiên bản App Engine này. Chúng tôi sẽ sớm thấy cuộc gọi đó.
Thêm định nghĩa hàm _get_gae_admins()
sau đây vào main.py
ngay bên dưới bản sao ứng dụng 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
Khi người dùng đăng nhập vào ứng dụng, những điều sau sẽ xảy ra:
- Google sẽ kiểm tra nhanh dựa trên mẫu trên web sau khi người dùng đăng nhập vào Firebase.
- Khi trạng thái xác thực thay đổi trong mẫu, lệnh gọi
fetch()
kiểu Ajax được thực hiện đến/is_admin
, trong đó trình xử lý là hàm tiếp theo,is_admin()
. - Mã thông báo của mã nhận dạng Firebase được chuyển vào phần nội dung POST cho
is_admin()
. Thao tác này sẽ lấy mã này khỏi các tiêu đề và gọi SDK quản trị Firebase để xác thực mã đó. Nếu đó là người dùng hợp lệ, hãy trích xuất địa chỉ email của họ và kiểm tra xem đó có phải là người dùng quản trị hay không. - Sau đó, kết quả Boolean được trả về mẫu là 200 thành công.
Thêm is_admin()
vào main.py
ngay sau _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
Tất cả mã từ cả hai hàm này đều phải sao chép chức năng có sẵn từ dịch vụ Người dùng, cụ thể là hàm is_current_user_admin()
. Lệnh gọi hàm này trong Mô-đun 20 đã thực hiện toàn bộ công việc khó khăn, không giống như Mô-đun 21 khi chúng ta triển khai giải pháp thay thế. Tin vui là ứng dụng không còn phụ thuộc vào một dịch vụ chỉ dành cho App Engine, tức là bạn có thể chuyển ứng dụng của mình sang Cloud Run hoặc các dịch vụ khác. Ngoài ra, bạn cũng có thể thay đổi định nghĩa về "người dùng quản trị" cho ứng dụng của riêng bạn chỉ bằng cách chuyển sang các vai trò mong muốn trong _TARGETS
, còn dịch vụ Người dùng được mã hoá cứng cho các vai trò quản trị viên App Engine.
Khởi chạy tính năng Xác thực Firebase và lưu người dùng quản trị vào bộ nhớ đệm của App Engine
Chúng ta có thể đã khởi chạy tính năng Xác thực Firebase ở trên cùng gần vị trí mà ứng dụng Flask được khởi chạy và ứng dụng Cloud NDB API được tạo, nhưng không cần phải làm cho đến khi tất cả mã quản trị đã được xác định, chính là vị trí hiện tại của chúng ta. Tương tự, giờ đây _get_gae_admins()
đã được định nghĩa, hãy gọi hàm này để lưu danh sách người dùng quản trị vào bộ nhớ đệm.
Thêm các dòng sau ngay bên dưới phần nội dung hàm is_admin()
:
# initialize Firebase and fetch set of App Engine admins
initialize_app()
_ADMINS = _get_gae_admins()
Xem thông tin cập nhật về mô hình dữ liệu
Mô hình dữ liệu Visit
không thay đổi. Để truy cập vào kho dữ liệu, bạn phải sử dụng rõ ràng trình quản lý ngữ cảnh ứng dụng Cloud NDB API, ds_client.context()
. Trong đoạn mã, điều này có nghĩa là bạn gói các lệnh gọi Datastore trong cả store_visit()
và fetch_visits()
bên trong các khối with
Python. Bản cập nhật này giống với Mô-đun 2. Thực hiện các thay đổi như sau:
TRƯỚC KHI:
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)
SAU KHI:
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)
Di chuyển logic đăng nhập của người dùng sang mẫu web
Dịch vụ Người dùng App Engine là phía máy chủ trong khi Dịch vụ Xác thực Firebase và Cloud Identity Platform chủ yếu ở phía máy khách. Do đó, phần lớn mã quản lý người dùng trong ứng dụng Mô-đun 20 chuyển sang mẫu web của Mô-đun 21.
Trong main.py
, ngữ cảnh web truyền 5 phần dữ liệu thiết yếu đến mẫu, 4 phần dữ liệu đầu tiên được liệt kê gắn liền với hoạt động quản lý người dùng và khác nhau tuỳ thuộc vào việc người dùng đã đăng nhập hay chưa:
who
– email của người dùng nếu đã đăng nhập hoặc người dùng nếu khôngadmin
– huy hiệu (quản trị viên) nếu người dùng đã đăng nhập là quản trị viênsign
– hiện nút Đăng nhập hoặc Đăng xuấtlink
— liên kết đăng nhập hoặc đăng xuất khi nhấp vào nútvisits
— lượt truy cập gần đây nhất
TRƯỚC KHI:
@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)
Toàn bộ hoạt động quản lý người dùng sẽ chuyển sang mẫu web, vì vậy chúng ta chỉ còn lại các lượt truy cập, đưa trình xử lý chính trở lại giao diện mà chúng ta đã có trong ứng dụng Mô-đun 1:
SAU KHI:
@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)
Cập nhật mẫu web
Tất cả nội dung cập nhật từ phần trước trong mẫu trông như thế nào? Chúng tôi chủ yếu di chuyển hoạt động quản lý người dùng từ ứng dụng sang tính năng Xác thực Firebase chạy trong mẫu và một phần cổng của tất cả mã mà chúng tôi đã chuyển sang JavaScript. Chúng tôi nhận thấy main.py
thu hẹp lại khá nhiều, vì vậy, dự kiến mức tăng trưởng tương tự vào templates/index.html
.
TRƯỚC KHI:
<!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>
Thay thế toàn bộ mẫu web bằng nội dung dưới đây:
SAU KHI:
<!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>
Có nhiều thành phần trong phần nội dung HTML này, vì vậy, hãy lấy từng thành phần một.
Nhập dữ liệu Firebase
Khi vẫn ở trong tiêu đề của tài liệu HTML, sau khi qua tiêu đề trang, hãy nhập các thành phần Firebase cần thiết. Các thành phần của Firebase hiện được chia thành nhiều mô-đun để tăng tính hiệu quả. Mã để khởi chạy Firebase được nhập từ mô-đun ứng dụng Firebase chính trong khi các chức năng quản lý tính năng xác thực Firebase, Google với vai trò là nhà cung cấp thông tin xác thực, đăng nhập và đăng xuất, cũng như thay đổi trạng thái xác thực "lệnh gọi lại" đều được nhập từ mô-đun Xác thực 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";
Cấu hình Firebase
Trước đó trong phần thiết lập Nền tảng nhận dạng của hướng dẫn này, bạn đã lưu apiKey
và authDomain
từ hộp thoại Chi tiết thiết lập ứng dụng. Thêm các giá trị đó vào biến firebaseConfig
trong phần tiếp theo. Chúng tôi có một đường liên kết đến phần hướng dẫn chi tiết hơn trong phần bình luận:
// 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",
};
Khởi chạy Firebase
Phần tiếp theo sẽ khởi chạy Firebase bằng thông tin cấu hình này.
// initialize Firebase app & auth components
initializeApp(firebaseConfig);
var auth = getAuth();
var provider = new GoogleAuthProvider();
//provider.setCustomParameters({prompt: 'select_account'});
Điều này giúp bạn có thể sử dụng Google làm nhà cung cấp dịch vụ xác thực và cung cấp tùy chọn có chú thích để hiển thị bộ chọn tài khoản ngay cả khi chỉ có một Tài khoản Google được đăng ký trong phiên trình duyệt của bạn. Nói cách khác, khi có nhiều tài khoản, bạn sẽ nhìn thấy "công cụ chọn tài khoản" này như mong đợi: Tuy nhiên, nếu chỉ có một người dùng trong phiên, thì quá trình đăng nhập sẽ tự động hoàn tất mà không cần bất kỳ sự tương tác nào của người dùng. (Cửa sổ bật lên xuất hiện rồi biến mất.) Bạn có thể buộc hộp thoại bộ chọn tài khoản hiển thị cho một người dùng (thay vì đăng nhập ngay vào ứng dụng) bằng cách huỷ nhận xét về dòng thông số tuỳ chỉnh. Nếu bạn bật chế độ này, thì ngay cả những người dùng một người dùng cũng sẽ thấy bộ chọn tài khoản:
Chức năng đăng nhập và đăng xuất
Các dòng mã tiếp theo tạo thành hàm để nhấp vào nút đăng nhập hoặc đăng xuất:
// define login and logout button functions
function login() {
signInWithPopup(auth, provider);
};
function logout() {
signOut(auth);
};
Thao tác đăng nhập và đăng xuất
Phần chính cuối cùng trong khối <script>
này là hàm được gọi cho mọi thay đổi xác thực (đăng nhập hoặc đăng xuất).
// 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>
Mã trong Mô-đun 20 xác định xem có gửi một "người dùng đã đăng nhập" hay không bối cảnh mẫu so với "người dùng đã đăng xuất" ngữ cảnh được chuyển đổi ở đây. Điều kiện ở trên cùng sẽ tạo ra true
nếu người dùng đăng nhập thành công, kích hoạt các hành động sau:
- Địa chỉ email của người dùng được đặt để hiển thị.
- Nút Đăng nhập sẽ chuyển thành Đăng xuất.
- Lệnh gọi kiểu Ajax đến
/is_admin
được thực hiện để xác định xem có hiển thị huy hiệu người dùng quản trị(admin)
hay không.
Khi người dùng đăng xuất, mệnh đề else
sẽ được thực thi để đặt lại tất cả thông tin người dùng:
- Tên người dùng được đặt là user
- Mọi huy hiệu của quản trị viên đã bị xoá
- Nút Đăng xuất đã chuyển lại thành Đăng nhập
Biến mẫu
Sau khi phần tiêu đề kết thúc, phần nội dung chính bắt đầu bằng các biến mẫu được thay thế bằng các phần tử HTML có thể thay đổi khi cần:
- Tên người dùng được hiển thị
- Huy hiệu quản trị viên
(admin)
(nếu có) - Nút Đăng nhập hoặc Đăng xuất
<body>
<p>
Welcome, <span id="who"></span> <span id="admin"><code>(admin)</code></span>
<button id="logbtn"></button>
</p><hr>
Lượt truy cập gần đây nhất và các biến phần tử HTML
Mã lượt truy cập gần đây nhất không thay đổi và khối <script>
cuối cùng sẽ đặt biến cho các phần tử HTML thay đổi đối với hoạt động đăng nhập và đăng xuất được liệt kê ở trên:
<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>
Đến đây, bạn không còn phải thực hiện những thay đổi cần thiết trong mẫu web và ứng dụng để chuyển từ App Engine NDB và API Người dùng sang Cloud NDB và Nền tảng nhận dạng cũng như nâng cấp lên Python 3. Chúc mừng bạn đã đến với ứng dụng mẫu Mô-đun 21 mới! Bạn có thể xem phiên bản của chúng tôi trong thư mục kho lưu trữ Mô-đun 21b.
Phần tiếp theo của lớp học lập trình này là không bắt buộc (*) và chỉ dành cho những người dùng có ứng dụng phải tiếp tục sử dụng Python 2. Hướng dẫn bạn thực hiện các bước cần thiết để có được ứng dụng Python 2 Module 21 đang hoạt động.
6. *Điều chỉnh cho phiên bản cũ của Python 2
Phần không bắt buộc này dành cho các nhà phát triển di chuyển Nền tảng nhận dạng nhưng phải tiếp tục chạy trên môi trường thời gian chạy Python 2. Nếu bạn không lo ngại về điều này, hãy bỏ qua phần này.
Để tạo một phiên bản Python 2 hoạt động được của ứng dụng Mô-đun 21, bạn cần có:
- Yêu cầu về thời gian chạy: Các tệp cấu hình hỗ trợ Python 2 và bắt buộc thực hiện các thay đổi trong ứng dụng chính để tránh việc không tương thích với Python 3
- Thay đổi nhỏ về thư viện: Python 2 không được dùng nữa trước khi một số tính năng bắt buộc được thêm vào thư viện ứng dụng Resource Manager (Trình quản lý tài nguyên). Do đó, bạn cần có một cách khác để truy cập vào chức năng còn thiếu đó.
Hãy thực hiện các bước đó ngay bây giờ, bắt đầu với cấu hình.
Khôi phục appengine_config.py
Ở phần trước của hướng dẫn này, bạn đã được hướng dẫn cách xoá appengine_config.py
vì thời gian chạy Python 3 App Engine không sử dụng mã này. Đối với Python 2, bạn không chỉ phải giữ nguyên API này mà còn cần cập nhật appengine_config.py
của Mô-đun 20 để hỗ trợ việc sử dụng thư viện bên thứ ba tích hợp sẵn, cụ thể là grpcio
và setuptools
. Bạn cần phải có các gói này bất cứ khi nào ứng dụng App Engine của bạn sử dụng các thư viện ứng dụng Cloud như các thư viện dành cho Cloud NDB và Cloud Resource Manager.
Bạn sẽ thêm các gói đó vào app.yaml
trong giây lát, nhưng để ứng dụng của bạn truy cập vào các gói đó, hàm pkg_resources.working_set.add_entry()
từ setuptools
phải được gọi. Điều này cho phép các thư viện bên thứ ba đã sao chép (tự nhóm hoặc cung cấp) được cài đặt trong thư mục lib
có thể giao tiếp với các thư viện tích hợp.
Triển khai các nội dung cập nhật sau đây cho tệp appengine_config.py
để thực hiện những thay đổi này:
TRƯỚC KHI:
from google.appengine.ext import vendor
# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)
Chỉ riêng mã này thì không đủ để hỗ trợ việc sử dụng setuptools
và grpcio
. Cần thêm một vài dòng nữa, vì vậy, hãy cập nhật appengine_config.py
để thành phần này như sau:
SAU KHI:
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)
Bạn có thể xem thêm thông tin về những thay đổi cần thiết để hỗ trợ thư viện ứng dụng Cloud trong tài liệu về việc di chuyển các dịch vụ đi kèm.
app.yaml
Tương tự như appengine_config.py
, tệp app.yaml
phải được khôi phục về một tệp hỗ trợ Python 2. Hãy bắt đầu từ app.yaml
của Mô-đun 20 gốc:
TRƯỚC KHI:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
Ngoài setuptools
và grpcio
như đã đề cập trước đó, còn có một phần phụ thuộc (không liên quan rõ ràng đến việc di chuyển Nền tảng danh tính) yêu cầu sử dụng thư viện ứng dụng Cloud Storage và thư viện đó cần có một gói khác tích hợp của bên thứ ba là ssl
. Thêm cả ba thành phần vào phần libraries
mới, chọn "mới nhất" phiên bản có sẵn của các gói đó, lên app.yaml
:
SAU KHI:
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
Đối với Mô-đun 21, chúng tôi đã thêm tính năng Xác thực của Google, Cloud NDB, Cloud Resource Manager và SDK quản trị của Firebase vào Python 3 requirements.txt
. Tình huống của Python 2 phức tạp hơn:
- API Trình quản lý tài nguyên cung cấp chức năng chính sách cho phép cần thiết cho ứng dụng mẫu. Rất tiếc, tính năng hỗ trợ này chưa có trong phiên bản Python 2 cuối cùng của thư viện ứng dụng Cloud Resource Manager. (Chỉ có trong phiên bản Python 3.)
- Do đó, bạn cần phải có một cách khác để truy cập vào tính năng này từ API. Giải pháp là sử dụng thư viện ứng dụng Google API cấp thấp hơn để giao tiếp với API. Để chuyển sang thư viện ứng dụng này, hãy thay thế
google-cloud-resource-manager
bằng góigoogle-api-python-client
ở cấp thấp hơn. - Vì Python 2 đã ngừng hoạt động, biểu đồ phần phụ thuộc hỗ trợ Mô-đun 21 yêu cầu khoá một số gói nhất định với các phiên bản cụ thể. Một số gói phải được gọi ngay cả khi các gói đó không được chỉ định trong
app.yaml
trong Python 3.
TRƯỚC KHI:
flask
Bắt đầu từ requirements.txt
của Mô-đun 20, hãy cập nhật thành như sau để ứng dụng Mô-đun 21 hoạt động:
SAU KHI:
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
Số gói và số phiên bản sẽ được cập nhật trong kho lưu trữ khi các phần phụ thuộc thay đổi, nhưng app.yaml
này là đủ cho một ứng dụng đang hoạt động tại thời điểm viết bài này.
Các nội dung cập nhật khác về cấu hình
Nếu bạn chưa xoá thư mục lib
trước đó trong lớp học lập trình này, hãy xoá ngay. Với requirements.txt
mới cập nhật, hãy phát hành lệnh quen thuộc này để cài đặt các yêu cầu sau vào lib
:
pip install -t lib -r requirements.txt # or pip2
Nếu đã cài đặt cả Python 2 và 3 trên hệ thống phát triển, bạn có thể phải sử dụng pip2
thay vì pip
.
Sửa đổi mã xử lý ứng dụng
May mắn thay, hầu hết thay đổi bắt buộc đều nằm trong các tệp cấu hình. Thay đổi duy nhất cần thiết trong mã xử lý ứng dụng là một bản cập nhật nhỏ để sử dụng thư viện ứng dụng Google API cấp thấp hơn thay vì thư viện ứng dụng Trình quản lý tài nguyên để truy cập API. Bạn không cần phải cập nhật mẫu web templates/index.html
.
Cập nhật các lệnh nhập và khởi chạy
Thay thế thư viện ứng dụng Trình quản lý tài nguyên (google.cloud.resourcemanager
) bằng thư viện ứng dụng API của Google (googleapiclient.discovery
), như minh hoạ bên dưới:
TRƯỚC KHI:
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
SAU KHI:
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
Dịch vụ hỗ trợ dành cho người dùng quản trị của App Engine
Cần một vài thay đổi trong _get_gae_admins()
để hỗ trợ việc sử dụng thư viện ứng dụng cấp thấp hơn. Trước tiên, hãy thảo luận về những gì sẽ thay đổi, sau đó cung cấp cho bạn tất cả các mã để cập nhật.
Mã Python 2 yêu cầu sử dụng cả thông tin xác thực và mã dự án được google.auth.default()
trả về. Thông tin đăng nhập không được sử dụng trong Python 3, vì vậy, thông tin này được gán cho biến giả gạch dưới chung ( _
). Vì cần có phiên bản Python 2, hãy thay đổi dấu gạch dưới thành CREDS
. Ngoài ra, thay vì tạo ứng dụng API Trình quản lý tài nguyên, bạn sẽ tạo điểm cuối dịch vụ API, tương tự như khái niệm ứng dụng API, vì vậy, chúng ta sẽ giữ nguyên tên biến (rm_client
). Có một điểm khác biệt là việc tạo thực thể cho điểm cuối của dịch vụ cần có thông tin đăng nhập (CREDS
).
Những thay đổi này được phản ánh trong mã bên dưới:
TRƯỚC KHI:
_, PROJ_ID = default( # Application Default Credentials and project ID
['https://www.googleapis.com/auth/cloudplatformprojects.readonly'])
rm_client = resourcemanager.ProjectsClient()
SAU KHI:
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)
Điểm khác biệt khác là thư viện ứng dụng Trình quản lý tài nguyên trả về các đối tượng chính sách cho phép sử dụng ký hiệu thuộc tính dấu chấm trong khi thư viện ứng dụng cấp thấp trả về từ điển Python trong đó sử dụng dấu ngoặc vuông ( [ ]
), ví dụ: sử dụng binding.role
cho thư viện ứng dụng Trình quản lý tài nguyên so với binding['role']
cho thư viện cấp thấp hơn. Mã số trước cũng sử dụng "underscore_dựa" so với thư viện cấp thấp hơn thích "CamelCased" cùng với một cách hơi khác để truyền tham số API.
Những khác biệt về cách sử dụng được thể hiện dưới đây:
TRƯỚC KHI:
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)
SAU KHI:
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'])
Tập hợp tất cả những thay đổi này lại với nhau, thay thế _get_gae_admins()
Python 3 bằng phiên bản Python 2 tương đương sau:
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
Hàm is_admin()
không yêu cầu cập nhật vì hàm này dựa vào _get_gae_admins()
đã được cập nhật.
Điều này kết thúc những thay đổi cần thiết để điều chỉnh cho phiên bản cũ ứng dụng Python 3 Module 21 sang Python 2. Chúc mừng bạn đã đến với ứng dụng mẫu Mô-đun 21 mà bạn cập nhật! Bạn sẽ tìm thấy tất cả mã trong thư mục kho lưu trữ Mô-đun 21a.
7. Tóm tắt/Dọn dẹp
Bước cuối cùng trong lớp học lập trình này là đảm bảo các tài khoản chính (người dùng hoặc tài khoản dịch vụ) đang chạy ứng dụng này có quyền thích hợp để làm vậy, sau đó triển khai ứng dụng để xác nhận rằng ứng dụng hoạt động như mong đợi và các thay đổi sẽ được phản ánh trong kết quả.
Có thể đọc chính sách cho phép IAM
Trước đó, chúng tôi đã giới thiệu với bạn 4 vai trò bắt buộc để được công nhận là người dùng quản trị của App Engine, nhưng bây giờ có 1/5 vai trò mà bạn cần nắm bắt:
roles/viewer
roles/editor
roles/owner
roles/appengine.appAdmin
roles/resourcemanager.projectIamAdmin
(đối với những người quản lý có quyền truy cập vào chính sách cho phép quản lý danh tính và quyền truy cập (IAM))
Vai trò roles/resourcemanager.projectIamAdmin
cho phép người dùng chính xác định xem người dùng cuối có phải là thành viên của bất kỳ vai trò quản trị viên nào trên App Engine hay không. Nếu bạn không có gói thành viên trong roles/resourcemanager.projectIamAdmin
, các lệnh gọi đến Cloud Resource Manager API để nhận chính sách cho phép sẽ không thực hiện được.
Bạn không cần làm gì ở đây vì ứng dụng của bạn sẽ chạy trong tài khoản dịch vụ mặc định của App Engine. Tài khoản này sẽ tự động được cấp tư cách thành viên trong vai trò này. Ngay cả khi sử dụng tài khoản dịch vụ mặc định trong giai đoạn phát triển, bạn vẫn nên tạo và sử dụng tài khoản dịch vụ do người dùng quản lý có các quyền tối thiểu cần thiết để ứng dụng của bạn hoạt động đúng cách. Để cấp tư cách thành viên cho một tài khoản dịch vụ đó, hãy chạy lệnh sau:
$ 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
là mã dự án trên Cloud và USR_MGD_SVC_ACCT@PROJ_ID.iam.gserviceaccount.com
là tài khoản dịch vụ do người dùng quản lý mà bạn tạo cho ứng dụng của mình. Lệnh này sẽ đưa ra chính sách IAM đã cập nhật cho dự án của bạn, qua đó bạn có thể xác nhận tài khoản dịch vụ có tư cách thành viên trong roles/resourcemanager.projectIamAdmin
. Để biết thêm thông tin, hãy xem tài liệu tham khảo. Lặp lại, bạn không cần đưa ra lệnh đó trong lớp học lập trình này, nhưng hãy lưu lệnh này làm tài liệu tham khảo để hiện đại hoá ứng dụng của riêng bạn.
Triển khai và xác minh ứng dụng
Tải ứng dụng lên đám mây bằng lệnh gcloud app deploy
tiêu chuẩn. Sau khi triển khai, bạn sẽ thấy chức năng gần giống với ứng dụng Mô-đun 20, ngoại trừ việc bạn đã thay thế thành công dịch vụ Người dùng App Engine bằng Cloud Identity Platform (và Xác thực Firebase) để quản lý người dùng:
Một điểm khác biệt so với Mô-đun 20 là việc nhấp vào kết quả Đăng nhập trong một cửa sổ bật lên thay vì một lệnh chuyển hướng. Như vậy, bạn sẽ thấy một số ảnh chụp màn hình ở bên dưới. Tuy nhiên, giống như Mô-đun 20, hành vi hơi khác một chút tuỳ thuộc vào số lượng Tài khoản Google đã được đăng ký với trình duyệt.
Nếu chưa có người dùng nào đăng ký với trình duyệt hoặc có một người dùng chưa đăng nhập, một cửa sổ bật lên chung để đăng nhập bằng Google sẽ xuất hiện:
Nếu một người dùng được đăng ký bằng trình duyệt của bạn nhưng lại đăng nhập ở nơi khác thì sẽ không có hộp thoại nào xuất hiện (hoặc hộp thoại bật lên và đóng ngay lập tức) và ứng dụng sẽ chuyển sang trạng thái đã đăng nhập (hiển thị email người dùng và nút Đăng xuất).
Một số nhà phát triển có thể muốn cung cấp công cụ chọn tài khoản, ngay cả đối với một người dùng duy nhất:
Để triển khai việc này, hãy huỷ nhận xét về dòng provider.setCustomParameters({prompt: 'select_account'});
trong mẫu web như mô tả ở trên.
Nếu có nhiều người dùng, hộp thoại bộ chọn tài khoản sẽ bật lên (xem bên dưới). Nếu chưa đăng nhập, người dùng sẽ được nhắc. Nếu bạn đã đăng nhập, cửa sổ bật lên sẽ biến mất và ứng dụng sẽ chuyển sang trạng thái đã đăng nhập.
Trạng thái đã đăng nhập của Mô-đun 21 trông giống với giao diện người dùng của Mô-đun 20:
Điều này cũng đúng đối với trường hợp người dùng quản trị đã đăng nhập:
Không giống như Mô-đun 21, Mô-đun 20 luôn truy cập logic cho nội dung mẫu web từ ứng dụng (mã phía máy chủ). Một lỗi của Mô-đun 20 là một lượt truy cập được đăng ký khi người dùng cuối truy cập vào ứng dụng lần đầu tiên và một lượt truy cập khác được đăng ký khi người dùng đăng nhập.
Đối với Mô-đun 21, logic đăng nhập chỉ diễn ra trong mẫu web (mã phía máy khách). Bạn không cần phải di chuyển phía máy chủ để xác định nội dung cần hiển thị. Lệnh gọi duy nhất được thực hiện đến máy chủ là kiểm tra người dùng quản trị sau khi người dùng cuối đăng nhập. Điều này có nghĩa là hoạt động đăng nhập và đăng xuất sẽ không đăng ký thêm lượt truy cập, do đó, danh sách lượt truy cập gần đây nhất luôn cố định cho các thao tác quản lý người dùng. Lưu ý rằng các ảnh chụp màn hình ở trên hiển thị cùng một nhóm 4 lượt truy cập trên nhiều lần đăng nhập của người dùng.
Ảnh chụp màn hình của Mô-đun 20 minh hoạ "lỗi truy cập hai lần" ở đầu lớp học lập trình này. Các nhật ký lượt truy cập riêng biệt được hiển thị cho mỗi thao tác đăng nhập hoặc đăng xuất. Kiểm tra dấu thời gian của lượt truy cập gần đây nhất cho từng ảnh chụp màn hình hiển thị thứ tự thời gian.
Dọn dẹp
Giải pháp chung
Nếu bạn đã hoàn tất, chúng tôi khuyên bạn nên tắt ứng dụng App Engine để tránh phát sinh thanh toán. Tuy nhiên, nếu bạn muốn kiểm tra hoặc thử nghiệm thêm, nền tảng App Engine có hạn mức miễn phí, và bạn sẽ không bị tính phí, miễn là bạn không vượt quá cấp sử dụng đó. Đó là cho dịch vụ điện toán nhưng bạn cũng có thể bị tính phí cho các dịch vụ có liên quan của App Engine, vì vậy hãy xem trang giá của dịch vụ này để biết thêm thông tin. Nếu quá trình di chuyển này liên quan đến các dịch vụ khác trên Google Cloud, thì những dịch vụ đó sẽ được tính phí riêng. Trong cả hai trường hợp (nếu có), hãy xem phần "Dành riêng cho lớp học lập trình này" phần dưới đây.
Để công bố đầy đủ thông tin, việc triển khai cho một nền tảng điện toán không máy chủ của Google Cloud như App Engine sẽ làm phát sinh chi phí bản dựng và bộ nhớ thấp. Cloud Build cũng có hạn mức miễn phí riêng, tương tự như Cloud Storage. Việc lưu trữ hình ảnh đó sẽ sử dụng hết một phần hạn mức đó. Tuy nhiên, bạn có thể sống ở một khu vực không có bậc miễn phí như vậy, vì vậy hãy chú ý đến mức sử dụng bộ nhớ của bạn để giảm thiểu chi phí tiềm ẩn. "Thư mục" cụ thể trên Cloud Storage bạn nên xem xét, bao gồm:
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
- Các đường liên kết lưu trữ ở trên phụ thuộc vào
PROJECT_ID
vàLOC
của bạn, chẳng hạn như "us
" nếu ứng dụng của bạn được lưu trữ ở Hoa Kỳ.
Mặt khác, nếu bạn không định tiếp tục sử dụng ứng dụng này hoặc các lớp học lập trình di chuyển khác có liên quan và muốn xoá hoàn toàn mọi thứ, hãy ngừng dự án của bạn.
Dành riêng cho lớp học lập trình này
Các dịch vụ được liệt kê dưới đây là những dịch vụ dành riêng cho lớp học lập trình này. Hãy tham khảo tài liệu của từng sản phẩm để biết thêm thông tin:
- Dịch vụ App Engine Datastore do Cloud Datastore (Cloud Firestore ở chế độ Datastore) cung cấp, cũng có một bậc miễn phí; hãy xem trang giá của YouTube để biết thêm thông tin.
- Mức độ "miễn phí" của việc sử dụng Cloud Identity Platform tuỳ thuộc vào việc bạn sử dụng dịch vụ nào của Google. Hãy xem trang giá để biết thêm chi tiết.
- Bạn có thể sử dụng miễn phí Cloud Resource Manager API đối với hầu hết các phần trên trang giá của dịch vụ này.
Các bước tiếp theo
Ngoài hướng dẫn này, bạn cũng cần cân nhắc những mô-đun di chuyển khác tập trung vào việc ngừng sử dụng các dịch vụ cũ theo gói:
- Mô-đun 2: di chuyển từ App Engine
ndb
sang Cloud NDB - Mô-đun 7-9: di chuyển từ Hàng đợi tác vụ của App Engine (tác vụ đẩy) sang Cloud Tasks
- Mô-đun 12-13: di chuyển từ App Engine Memcache sang Cloud Memorystore
- Mô-đun 15-16: di chuyển từ App Engine Blobstore sang Cloud Storage
- Mô-đun 18-19: di chuyển từ Hàng đợi tác vụ của App Engine (Tác vụ kéo) sang Cloud Pub/Sub
App Engine không còn là nền tảng không máy chủ duy nhất trên Google Cloud nữa. Nếu bạn có một ứng dụng App Engine nhỏ hoặc một ứng dụng có chức năng hạn chế và muốn biến ứng dụng đó thành một dịch vụ vi mô độc lập, hoặc bạn muốn chia một ứng dụng nguyên khối thành nhiều thành phần có thể sử dụng lại, thì đây là những lý do chính đáng để bạn cân nhắc chuyển sang Cloud Functions. Nếu việc tích hợp vùng chứa đã trở thành một phần trong quy trình phát triển ứng dụng, đặc biệt là khi quy trình đó bao gồm một quy trình CI/CD (tích hợp liên tục/phân phối hoặc triển khai liên tục), hãy cân nhắc chuyển sang Cloud Run. Những trường hợp này được đề cập trong các mô-đun sau:
- Di chuyển từ App Engine sang Cloud Functions: xem Học phần 11
- Di chuyển từ App Engine sang Cloud Run: xem Mô-đun 4 để vùng chứa ứng dụng của bạn bằng Docker, hoặc Mô-đun 5 để triển khai mà không cần vùng chứa, kiến thức về Docker hoặc
Dockerfile
Việc chuyển sang một nền tảng không máy chủ khác là không bắt buộc. Bạn nên cân nhắc các lựa chọn phù hợp nhất cho ứng dụng và trường hợp sử dụng của mình trước khi điều chỉnh bất cứ điều gì.
Bất kể bạn cân nhắc mô-đun di chuyển nào tiếp theo, bạn đều có thể truy cập vào tất cả nội dung của Trạm di chuyển không máy chủ (lớp học lập trình, video, mã nguồn [nếu có]) tại kho lưu trữ nguồn mở của chúng. README
của kho lưu trữ này cũng cung cấp hướng dẫn về những quá trình di chuyển cần xem xét và mọi "đơn đặt hàng" có liên quan Mô-đun di chuyển.
8. Tài nguyên khác
Dưới đây là các tài nguyên bổ sung để nhà phát triển tìm hiểu thêm về mô-đun này hoặc các mô-đun di chuyển có liên quan. Bạn có thể đưa ra ý kiến phản hồi về nội dung này ở bên dưới, tìm các đường liên kết đến mã nguồn và nhiều thông tin hữu ích khác của tài liệu.
Vấn đề/ý kiến phản hồi về lớp học lập trình
Nếu bạn gặp vấn đề với lớp học lập trình này, vui lòng tìm vấn đề của bạn trước khi gửi. Đường liên kết để tìm kiếm và báo cáo vấn đề mới:
Tài nguyên di chuyển
Bạn có thể tìm thấy các đường liên kết đến các thư mục repo cho Mô-đun 20 (START) và Mô-đun 21 (Finish) trong bảng bên dưới.
Codelab | Python 2 | Python 3 |
(không áp dụng) | ||
Mô-đun 21 (lớp học lập trình này) |
Tài liệu tham khảo trực tuyến
Dưới đây là các tài nguyên có liên quan cho hướng dẫn này:
Cloud Identity Platform và Cloud Marketplace
- Trang sản phẩm Identity Platform
- Xác thực Firebase
- Trang so sánh sản phẩm Nền tảng nhận dạng và Xác thực Firebase
- Thông tin về giá trên Nền tảng nhận dạng
- Hạn mức nền tảng Identity (và mức sử dụng không có công cụ)
- Thiết lập nhà cung cấp Nền tảng danh tính
- Trang sản phẩm Cloud Marketplace
- Trang Nền tảng nhận dạng trong Thị trường
Trình quản lý tài nguyên đám mây, Cloud IAM, SDK quản trị của Firebase
- Trang sản phẩm Trình quản lý tài nguyên
- Thông tin về giá của Trình quản lý tài nguyên
- Thư viện ứng dụng Trình quản lý tài nguyên
- Tổng quan về Cloud IAM (vai trò, chính sách cho phép, v.v.)
- SDK dành cho quản trị viên của Firebase (Python)
Người dùng App Engine, App Engine NDB, Cloud NDB, Cloud Datastore
- Tổng quan về người dùng App Engine
- Tài liệu về NDB của App Engine
- Kho lưu trữ NDB của App Engine
- Thư viện ứng dụng Cloud NDB
- Kho lưu trữ Cloud NDB
- Trang sản phẩm Cloud Datastore
- Thông tin về giá của Cloud Datastore
Các tài liệu tham khảo khác về Mô-đun di chuyển
- Giới thiệu Phụ lục di chuyển
- Tất cả "Trạm di chuyển không máy chủ" tài nguyên hỗ trợ
- Di chuyển sang tài liệu Python 3
- Mô-đun di chuyển 17 "Sử dụng các dịch vụ đi kèm trong thời gian chạy thế hệ thứ 2" lớp học lập trình
- Mô-đun di chuyển 20 "Thêm dịch vụ người dùng App Engine vào ứng dụng Flask" lớp học lập trình
Di chuyển App Engine
- Sử dụng thư viện của bên thứ ba trong các ứng dụng Python 2
- Các thay đổi đối với
app.yaml
trong thời gian chạy thế hệ thứ 2 (Python 3) - Hướng dẫn di chuyển NDB của Cloud
- Nội dung về việc di chuyển Cloud NDB
Nền tảng App Engine
- Tài liệu về App Engine
- Thời gian chạy của Python 2 App Engine (môi trường tiêu chuẩn)
- Sử dụng thư viện tích hợp sẵn App Engine trên Python 2 App Engine
- Thời gian chạy của Python 3 App Engine (môi trường tiêu chuẩn)
- Điểm khác biệt giữa Python 2 và 3 môi trường thời gian chạy của App Engine (môi trường tiêu chuẩn)
- Hướng dẫn di chuyển từ Python 2 sang 3 App Engine (môi trường chuẩn)
- Thông tin về giá và hạn mức của App Engine
- Ra mắt nền tảng App Engine thế hệ thứ hai (2018)
- So sánh đầu tiên và nền tảng thế hệ thứ hai
- Hỗ trợ dài hạn cho môi trường thời gian chạy cũ
- Mẫu di chuyển tài liệu
- Mẫu di chuyển do cộng đồng đóng góp
SDK đám mây
- SDK Google Cloud
- Công cụ dòng lệnh
gcloud
của Cloud SDK - Bật (và tắt) Google API
- Trình quản lý API bảng điều khiển Cloud (bật/tắt API)
- Bật API của Google bằng
gcloud
- Lập danh sách các API của Google bằng
gcloud
Thông tin khác về đám mây
- Python trên Google Cloud
- Tài liệu về thư viện ứng dụng Python
- Kho lưu trữ thư viện ứng dụng Python
- "Luôn miễn phí" cấp
- SDK đám mây
- Công cụ dòng lệnh
gcloud
của Cloud SDK - Tất cả tài liệu của Google Cloud
Video
- Trạm di chuyển không máy chủ
- Thám hiểm không máy chủ
- Đăng ký sử dụng Google Cloud Tech
- Đăng ký Google Developers
Giấy phép
Tác phẩm này được cấp phép theo Giấy phép chung Ghi nhận tác giả Creative Commons 2.0.