0
0
Lập trình
TT

3 Cạm Bẫy Khi Gọi API Cloud Run Bảo Vệ Bằng IAP Từ Chrome Extension (MV3)

Đăng vào 7 tháng trước

• 3 phút đọc

Giới thiệu

Trong bài viết này, chúng ta sẽ khám phá cách gọi một API Cloud Run được bảo vệ bằng IAP (Identity-Aware Proxy) từ một Chrome Extension sử dụng Manifest V3 (MV3). Bài viết không chỉ hướng dẫn bạn từng bước để thực hiện mà còn chỉ ra những cạm bẫy phổ biến mà bạn có thể gặp phải trong quá trình triển khai.

Mục tiêu

  • Sử dụng chrome.identity.launchWebAuthFlow để lấy Google ID token.
  • Gửi token dưới dạng Authorization: Bearer <token> đến endpoint Cloud Run được bảo vệ bằng IAP/IAM.
  • Xác minh audience của token trên server và lưu cache token với một khoảng thời gian hết hạn nhỏ trên client.

Tóm tắt

1. Lấy ID token (MV3)

Để bắt đầu, bạn cần một tệp background.js chứa mã sau:

javascript Copy
async function getIdToken() {
  const redirectUrl = chrome.identity.getRedirectURL();
  const u = new URL("https://accounts.google.com/o/oauth2/v2/auth");
  u.searchParams.set("client_id", "YOUR_OAUTH_CLIENT_ID.apps.googleusercontent.com");
  u.searchParams.set("response_type", "id_token");
  u.searchParams.set("scope", "openid email profile");
  u.searchParams.set("redirect_uri", redirectUrl);
  u.searchParams.set("nonce", String(Date.now()));
  u.searchParams.set("prompt", "select_account");

  const { url } = await chrome.identity.launchWebAuthFlow({ url: u.toString(), interactive: true });
  const params = new URLSearchParams(new URL(url).hash.substring(1));
  const idToken = params.get("id_token");
  if (!idToken) throw new Error("No id_token returned");
  return idToken;
}

Mini-cache (tùy chọn)

Để cải thiện hiệu suất, bạn có thể thêm mã sau để lưu trữ token:

javascript Copy
function decodePayload(jwt){const b=jwt.split('.')[1].replace(/-/g,'+').replace(/_/g,'/');return JSON.parse(atob(b));}
async function getCachedIdToken(){
  const now=Math.floor(Date.now()/1000);
  const {token,exp}=await chrome.storage.local.get(["token","exp"]);
  if(token && exp && (exp-300)>now) return token; // 5‑min buffer
  const fresh=await getIdToken(); const {exp:e}=decodePayload(fresh);
  await chrome.storage.local.set({token:fresh, exp:e}); return fresh;
}

2. Gọi API

Tiếp theo, bạn cần mã trong tệp popup.js để gọi API:

javascript Copy
document.getElementById("go").addEventListener("click", async () => {
  const token = await chrome.runtime.sendMessage({ type: "GET_TOKEN" });
  const res = await fetch("https://YOUR‑SERVICE‑HASH‑ue.a.run.app/run-secure-endpoint", {
    method: "POST",
    headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
    body: JSON.stringify({ url: (await chrome.tabs.query({active:true,currentWindow:true}))[0].url })
  });
  console.log(await res.text());
});

Và trong background.js:

javascript Copy
chrome.runtime.onMessage.addListener((m,_,send)=>{
  if(m?.type==="GET_TOKEN") getCachedIdToken().then(t=>send(t)).catch(e=>send({error:String(e)}));
  return true;
});

3. Xác minh trên Flask (Cloud Run)

Cuối cùng, mã xác minh token sẽ nằm trong tệp main.py:

python Copy
from flask import Flask, request, jsonify
from google.oauth2 import id_token
from google.auth.transport import requests as greq
import os

app = Flask(__name__)
IAP_AUDIENCE = os.environ.get("IAP_OAUTH_CLIENT_ID","")  # set this for IAP

def verify_google_id_token(tok:str)->dict:
  return id_token.verify_oauth2_token(tok, greq.Request(), audience=IAP_AUDIENCE)

@app.post("/run-secure-endpoint")
def run_secure():
  auth = request.headers.get("Authorization","")
  if not auth.startswith("Bearer "): return jsonify({"error":"missing bearer"}), 401
  try: payload = verify_google_id_token(auth.split()[1])
  except Exception as e: return jsonify({"error":"invalid token","detail":str(e)}), 401
  return jsonify({"ok": True, "email": payload.get("email")})

Những cạm bẫy phổ biến và cách khắc phục

  1. Lỗi 401 với IAP: Kiểm tra audience. Sử dụng IAP OAuth Client ID làm aud khi xác minh.
  2. Token id_token rỗng: Kiểm tra loại client OAuth2 (Web) và redirect URI từ getRedirectURL().
  3. Token hết hạn giữa phiên: Lưu cache với một khoảng đệm nhỏ (5 phút) và làm mới khi cần.
  4. CORS: Thêm Access-Control-Allow-Origin và cho phép header Authorization nếu bạn gọi từ script hoặc trang nội dung.

Cấu trúc repo tối thiểu

Copy
repo/
├─ extension/ (manifest.json, background.js, popup.{html,js})
└─ backend/   (main.py, requirements.txt, Dockerfile)

Kết luận

Bài viết này đã hướng dẫn bạn cách gọi API Cloud Run được bảo vệ bằng IAP từ Chrome Extension. Hy vọng rằng những thông tin và mã nguồn cung cấp sẽ giúp bạn vượt qua những cạm bẫy phổ biến. Nếu bạn cần hướng dẫn chi tiết hơn, hãy tìm kiếm bài viết hoặc case-study dài hơn của tôi sau này. Hãy bắt đầu ngay hôm nay và thực hiện dự án của bạn!

Thực hành tốt nhất và mẹo hiệu suất

  • Luôn xác minh audience của ID token trước khi sử dụng.
  • Sử dụng cache cho token để cải thiện hiệu suất và trải nghiệm người dùng.
  • Kiểm tra và xử lý các lỗi CORS để đảm bảo API hoạt động mượt mà từ các nguồn khác nhau.

Câu hỏi thường gặp (FAQ)

H: Làm thế nào để tôi lấy ID token?
Đ: Bạn có thể sử dụng hàm getIdToken() trong background.js để lấy ID token từ Google.

H: Tại sao tôi nhận được lỗi 401?
Đ: Lỗi 401 thường xảy ra do audience không đúng. Đảm bảo rằng bạn đã sử dụng IAP OAuth Client ID thích hợp.

Tài nguyên tham khảo

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào