Google Chat থেকে অনুরোধ যাচাই করুন

HTTP এন্ডপয়েন্টের উপর ভিত্তি করে তৈরি Google Chat অ্যাপগুলির জন্য, আপনার এন্ডপয়েন্টে পাঠানো অনুরোধগুলি Chat থেকেই আসছে কিনা, তা কীভাবে যাচাই করবেন, এই বিভাগে তা ব্যাখ্যা করা হয়েছে।

আপনার চ্যাট অ্যাপের এন্ডপয়েন্টে ইন্টারঅ্যাকশন ইভেন্ট পাঠাতে, গুগল আপনার সার্ভিসে অনুরোধ পাঠায়। অনুরোধটি যে গুগল থেকেই আসছে, তা যাচাই করার জন্য চ্যাট আপনার এন্ডপয়েন্টে পাঠানো প্রতিটি HTTPS অনুরোধের Authorization হেডারে একটি বেয়ারার টোকেন অন্তর্ভুক্ত করে। উদাহরণস্বরূপ:

POST
Host: yourappurl.com
Authorization: Bearer AbCdEf123456
Content-Type: application/json
User-Agent: Google-Dynamite

পূর্ববর্তী উদাহরণে থাকা AbCdEf123456 স্ট্রিংটি হলো বেয়ারার অথরাইজেশন টোকেন। এটি গুগল দ্বারা উৎপাদিত একটি ক্রিপ্টোগ্রাফিক টোকেন। চ্যাট অ্যাপটি কনফিগার করার সময় আপনি যে ধরনের অথেন্টিকেশন অডিয়েন্স নির্বাচন করেছেন, তার উপর বেয়ারার টোকেনের ধরণ এবং audience ফিল্ডের মান নির্ভর করে।

আপনি যদি ক্লাউড রান ফাংশন ব্যবহার করে আপনার চ্যাট অ্যাপটি তৈরি করে থাকেন, তাহলে ক্লাউড আইএএম স্বয়ংক্রিয়ভাবে টোকেন যাচাইকরণ করে। আপনাকে অবশ্যই গুগল চ্যাট পরিষেবা অ্যাকাউন্টটিকে একজন অনুমোদিত ইনভোকার হিসেবে যুক্ত করতে হবে। যদি আপনার অ্যাপ নিজস্ব HTTP সার্ভার ব্যবহার করে, তাহলে আপনি একটি ওপেন সোর্স গুগল এপিআই ক্লায়েন্ট লাইব্রেরি ব্যবহার করে আপনার বেয়ারার টোকেন যাচাই করতে পারেন।

যদি চ্যাট অ্যাপের জন্য টোকেনটি যাচাই করা না যায়, তাহলে আপনার পরিষেবাটির উচিত অনুরোধটির জবাবে একটি HTTPS রেসপন্স কোড 401 (Unauthorized) পাঠানো।

ক্লাউড রান ফাংশন ব্যবহার করে অনুরোধগুলি প্রমাণীকরণ করুন

যদি আপনার ফাংশন লজিক ক্লাউড রান ফাংশন ব্যবহার করে প্রয়োগ করা হয়, তাহলে আপনাকে অবশ্যই চ্যাট অ্যাপ সংযোগ সেটিং -এর 'অথেন্টিকেশন অডিয়েন্স' ফিল্ডে HTTP এন্ডপয়েন্ট URL নির্বাচন করতে হবে এবং নিশ্চিত করতে হবে যে কনফিগারেশনে থাকা HTTP এন্ডপয়েন্ট URL-টি ক্লাউড রান ফাংশন এন্ডপয়েন্টের URL-এর সাথে মিলে যায়।

এরপর, নিম্নলিখিত ধাপগুলো অনুসরণ করে আপনাকে chat@system.gserviceaccount.com গুগল চ্যাট পরিষেবা অ্যাকাউন্টটিকে একজন আহ্বানকারী হিসেবে অনুমোদন করতে হবে:

কনসোল

গুগল ক্লাউডে আপনার ফাংশন বা পরিষেবা স্থাপন করার পরে:

  1. গুগল ক্লাউড কনসোলে, ক্লাউড রান পৃষ্ঠায় যান:

    ক্লাউড রানে যান

  2. ক্লাউড রান সার্ভিসেস লিস্টে, রিসিভিং ফাংশনের পাশের চেকবক্সে ক্লিক করুন। (ফাংশনটিতে সরাসরি ক্লিক করবেন না।)

  3. স্ক্রিনের উপরের দিকে থাকা পারমিশন (Permissions)- এ ক্লিক করুন। পারমিশন প্যানেলটি খুলে যাবে।

  4. প্রিন্সিপাল যোগ করুন -এ ক্লিক করুন।

  5. 'New principals' ফিল্ডে chat@system.gserviceaccount.com লিখুন।

  6. 'Select a role' মেনু থেকে 'Cloud Run' রোলটি নির্বাচন করুন।

    ক্লাউড রান ইনভোকার

  7. সংরক্ষণ করুন- এ ক্লিক করুন।

জিক্লাউড

gcloud functions add-invoker-policy-binding কমান্ডটি ব্যবহার করুন:

gcloud functions add-invoker-policy-binding RECEIVING_FUNCTION \
  --member='serviceAccount:chat@system.gserviceaccount.com'

RECEIVING_FUNCTION জায়গায় আপনার চ্যাট অ্যাপের ফাংশনের নামটি বসান।

একটি আইডি টোকেন দিয়ে HTTP অনুরোধ প্রমাণীকরণ করুন

যদি চ্যাট অ্যাপ সংযোগ সেটিং -এর ‘অথেন্টিকেশন অডিয়েন্স’ ফিল্ডটি ‘HTTP এন্ডপয়েন্ট URL’- এ সেট করা থাকে, তাহলে অনুরোধের বিয়ারার অথরাইজেশন টোকেনটি একটি গুগল-স্বাক্ষরিত ওপেনআইডি কানেক্ট (OIDC) আইডি টোকেন হয়। email ফিল্ডটি chat@system.gserviceaccount.com এ সেট করা থাকে। ‘অথেন্টিকেশন অডিয়েন্স ’ ফিল্ডটি সেই URL-এ সেট করা থাকে, যা আপনি আপনার চ্যাট অ্যাপে অনুরোধ পাঠানোর জন্য গুগল চ্যাটকে কনফিগার করেছেন। উদাহরণস্বরূপ, যদি আপনার চ্যাট অ্যাপের কনফিগার করা এন্ডপয়েন্টটি https://example.com/app/ হয়, তাহলে আইডি টোকেনের ‘অথেন্টিকেশন অডিয়েন্স’ ফিল্ডটি হবে https://example.com/app/

আপনার HTTP এন্ডপয়েন্টটি যদি IAM-ভিত্তিক অথেনটিকেশন সমর্থন করে এমন কোনো সার্ভিসে (যেমন ক্লাউড রান) হোস্ট করা না থাকে, তাহলে এটিই প্রস্তাবিত অথেনটিকেশন পদ্ধতি। এই পদ্ধতি ব্যবহার করলে, আপনার HTTP সার্ভিসের যে এন্ডপয়েন্টে এটি চলছে তার URL সম্পর্কিত তথ্যের প্রয়োজন হয়, কিন্তু ক্লাউড প্রজেক্ট নম্বর সম্পর্কিত তথ্যের প্রয়োজন হয় না।

নিম্নলিখিত নমুনাগুলিতে দেখানো হয়েছে কিভাবে গুগল OAuth ক্লায়েন্ট লাইব্রেরি ব্যবহার করে যাচাই করা যায় যে, বেয়ারার টোকেনটি গুগল চ্যাট দ্বারা ইস্যু করা হয়েছে এবং এটি আপনার অ্যাপের জন্যই উদ্দিষ্ট।

জাভা

java/basic-app/src/main/java/com/google/chat/app/basic/App.java
String CHAT_ISSUER = "chat@system.gserviceaccount.com";
JsonFactory factory = JacksonFactory.getDefaultInstance();

GoogleIdTokenVerifier verifier =
    new GoogleIdTokenVerifier.Builder(new ApacheHttpTransport(), factory)
        .setAudience(Collections.singletonList(AUDIENCE))
        .build();

GoogleIdToken idToken = GoogleIdToken.parse(factory, bearer);
return idToken != null
    && verifier.verify(idToken)
    && idToken.getPayload().getEmailVerified()
    && idToken.getPayload().getEmail().equals(CHAT_ISSUER);

পাইথন

python/basic-app/main.py
# Bearer Tokens received by apps will always specify this issuer.
CHAT_ISSUER = 'chat@system.gserviceaccount.com'

try:
    # Verify valid token, signed by CHAT_ISSUER, intended for a third party.
    request = requests.Request()
    token = id_token.verify_oauth2_token(bearer, request, AUDIENCE)
    return token['email'] == CHAT_ISSUER

except:
    return False

নোড.জেএস

নোড/বেসিক-অ্যাপ/ইনডেক্স.জেএস
// Bearer Tokens received by apps will always specify this issuer.
const chatIssuer = 'chat@system.gserviceaccount.com';

// Verify valid token, signed by chatIssuer, intended for a third party.
try {
  const ticket = await client.verifyIdToken({
    idToken: bearer,
    audience: audience
  });
  return ticket.getPayload().email_verified
      && ticket.getPayload().email === chatIssuer;
} catch (unused) {
  return false;
}

প্রজেক্ট নম্বর JWT দিয়ে অনুরোধগুলি প্রমাণীকরণ করুন

যদি চ্যাট অ্যাপের সংযোগ সেটিং -এর ‘অথেন্টিকেশন অডিয়েন্স’ ফিল্ডটি Project Number -এ সেট করা থাকে, তাহলে অনুরোধের বিয়ারার অথরাইজেশন টোকেনটি হবে একটি সেলফ-সাইন্ড JSON ওয়েব টোকেন (JWT) , যা chat@system.gserviceaccount.com দ্বারা ইস্যু ও সাইন করা হয়েছে। audience ফিল্ডটি আপনার চ্যাট অ্যাপ তৈরি করতে ব্যবহৃত গুগল ক্লাউড প্রজেক্ট নম্বরে সেট করা থাকে। উদাহরণস্বরূপ, যদি আপনার চ্যাট অ্যাপের ক্লাউড প্রজেক্ট নম্বর 1234567890 হয়, তাহলে JWT-এর audience ফিল্ডটিও হবে 1234567890

এই প্রমাণীকরণ পদ্ধতিটি শুধুমাত্র তখনই সুপারিশ করা হয়, যদি আপনি HTTP এন্ডপয়েন্ট URL-এর পরিবর্তে অনুরোধ যাচাই করার জন্য ক্লাউড প্রজেক্ট নম্বর ব্যবহার করতে পছন্দ করেন। উদাহরণস্বরূপ, যদি আপনি একই ক্লাউড প্রজেক্ট নম্বর বজায় রেখে সময়ের সাথে সাথে এন্ডপয়েন্ট URL পরিবর্তন করতে চান, অথবা যদি আপনি একাধিক ক্লাউড প্রজেক্ট নম্বরের জন্য একই এন্ডপয়েন্ট ব্যবহার করতে চান এবং audience ফিল্ডটিকে ক্লাউড প্রজেক্ট নম্বরের একটি তালিকার সাথে তুলনা করতে চান।

নিম্নলিখিত নমুনাগুলিতে দেখানো হয়েছে কিভাবে গুগল OAuth ক্লায়েন্ট লাইব্রেরি ব্যবহার করে যাচাই করা যায় যে বেয়ারার টোকেনটি গুগল চ্যাট দ্বারা ইস্যু করা হয়েছে এবং এটি আপনার প্রোজেক্টের জন্যই নির্দিষ্ট।

জাভা

java/basic-app/src/main/java/com/google/chat/app/basic/App.java
String CHAT_ISSUER = "chat@system.gserviceaccount.com";
JsonFactory factory = JacksonFactory.getDefaultInstance();

GooglePublicKeysManager keyManagerBuilder =
    new GooglePublicKeysManager.Builder(new ApacheHttpTransport(), factory)
        .setPublicCertsEncodedUrl(
            "https://www.googleapis.com/service_accounts/v1/metadata/x509/" + CHAT_ISSUER)
        .build();

GoogleIdTokenVerifier verifier =
    new GoogleIdTokenVerifier.Builder(keyManagerBuilder).setIssuer(CHAT_ISSUER).build();

GoogleIdToken idToken = GoogleIdToken.parse(factory, bearer);
return idToken != null
    && verifier.verify(idToken)
    && idToken.verifyAudience(Collections.singletonList(AUDIENCE))
    && idToken.verifyIssuer(CHAT_ISSUER);

পাইথন

python/basic-app/main.py
# Bearer Tokens received by apps will always specify this issuer.
CHAT_ISSUER = 'chat@system.gserviceaccount.com'

try:
    # Verify valid token, signed by CHAT_ISSUER, intended for a third party.
    request = requests.Request()
    certs_url = 'https://www.googleapis.com/service_accounts/v1/metadata/x509/' + CHAT_ISSUER
    token = id_token.verify_token(bearer, request, AUDIENCE, certs_url)
    return token['iss'] == CHAT_ISSUER

except:
    return False

নোড.জেএস

নোড/বেসিক-অ্যাপ/ইনডেক্স.জেএস
// Bearer Tokens received by apps will always specify this issuer.
const chatIssuer = 'chat@system.gserviceaccount.com';

// Verify valid token, signed by CHAT_ISSUER, intended for a third party.
try {
  const response = await fetch('https://www.googleapis.com/service_accounts/v1/metadata/x509/' + chatIssuer);
  const certs = await response.json();
  await client.verifySignedJwtWithCertsAsync(
    bearer, certs, audience, [chatIssuer]);
  return true;
} catch (unused) {
  return false;
}