অনুমোদন ব্লক করার ট্রিগার


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

শুরু করার আগে

ব্লকিং ফাংশন ব্যবহার করতে, আপনাকে অবশ্যই Firebase প্রোজেক্টকে Firebase Authentication with Identity Platform ভার্সনে আপগ্রেড করতে হবে। আপনি এখনও আপগ্রেড না করে থাকলে, প্রথমে এটি করুন।

ব্লকিং ফাংশন বোঝা

আপনি এইসব ইভেন্টের জন্য ব্লকিং ফাংশন রেজিস্টার করতে পারবেন:

  • ব্যবহারকারী তৈরি হওয়ার আগে: কোনও নতুন ব্যবহারকারীকে Firebase Authentication ডেটাবেসে সেভ করার আগে এবং আপনার ক্লায়েন্ট অ্যাপে টোকেন রিটার্ন করার আগে ট্রিগার করে।

  • ব্যবহারকারী সাইন-ইন করার আগে: কোনও ব্যবহারকারীর ক্রেডেনশিয়াল যাচাই করার পরে ট্রিগার হয়, কিন্তু Firebase Authentication আপনার ক্লায়েন্ট অ্যাপে ID টোকেন ফেরত পাঠানোর আগে। আপনার অ্যাপে মাল্টি-ফ্যাক্টর যাচাইকরণ ব্যবহার করা হলে, ব্যবহারকারী তার দ্বিতীয় ফ্যাক্টর যাচাই করার পরে ফাংশন ট্রিগার হয়। মনে রাখবেন, নতুন ব্যবহারকারী তৈরি করা হলে এই দুটি ইভেন্টই ট্রিগার হয়।

  • ইমেল পাঠানোর আগে (শুধুমাত্র Node.js): কোনও ব্যবহারকারীকে ইমেল (যেমন, সাইন-ইন বা পাসওয়ার্ড রিসেট করার ইমেল) পাঠানোর আগে ট্রিগার করে।

  • এসএমএস মেসেজ পাঠানোর আগে (শুধুমাত্র Node.js): কোনও ব্যবহারকারীকে এসএমএস মেসেজ পাঠানোর আগে ট্রিগার করে। মাল্টি-ফ্যাক্টর যাচাইকরণের মতো ক্ষেত্রে এটি প্রযোজ্য।

ব্লকিং ফাংশন ব্যবহার করার সময় নিম্নলিখিত বিষয়গুলি মনে রাখবেন:

  • আপনার ফাংশনকে ৭ সেকেন্ডের মধ্যে উত্তর দিতে হবে। ৭ সেকেন্ড পরে, Firebase Authentication একটি সমস্যা রিটার্ন করে এবং ক্লায়েন্ট অপারেশন ব্যর্থ হয়।

  • 200 ছাড়া অন্য HTTP রেসপন্স কোড আপনার ক্লায়েন্ট অ্যাপে পাস করা হয়। নিশ্চিত করুন যে আপনার ফাংশন থেকে পাওয়া যেকোনও সমস্যা আপনার ক্লায়েন্ট কোড হ্যান্ডেল করতে পারে।

  • ফাংশন আপনার প্রজেক্টের সব ব্যবহারকারীর ক্ষেত্রে প্রযোজ্য, এর মধ্যে কোনও টেন্যান্টে থাকা ব্যবহারকারীও অন্তর্ভুক্ত। Firebase Authentication আপনার ফাংশনকে ব্যবহারকারীদের সম্পর্কে তথ্য প্রদান করে, যার মধ্যে তারা যে কোনও টেন্যান্টের অন্তর্ভুক্ত, যাতে আপনি সেই অনুযায়ী উত্তর দিতে পারেন।

  • কোনও অ্যাকাউন্টের সাথে অন্য কোনও পরিচয় প্রদানকারীকে লিঙ্ক করলে, রেজিস্টার করা যেকোনও beforeUserSignedIn ফাংশন আবার ট্রিগার হয়।

  • পরিচয় গোপন রাখা ও কাস্টম যাচাইকরণ ব্লক করার ফাংশন ট্রিগার করে না।

ব্লকিং ফাংশন ডেপ্লয় করা

ব্যবহারকারী যাচাইকরণ ফ্লোতে আপনার কাস্টম কোড যোগ করতে, ব্লকিং ফাংশন ডেপ্লয় করুন। আপনার ব্লকিং ফাংশন প্রয়োগ করা হয়ে গেলে, যাচাইকরণ ও ব্যবহারকারী তৈরি করার প্রসেস সম্পূর্ণ করতে আপনার কাস্টম কোডকে সফলভাবে কাজ করতে হবে।

আপনি যেভাবে অন্য কোনও ফাংশন ডেপ্লয় করেন, ঠিক সেইভাবেই কোনও ব্লকিং ফাংশন ডেপ্লয় করেন। (বিবরণের জন্য Cloud Functions শুরু করা পৃষ্ঠা দেখুন )। এককথায়:

  1. টার্গেট করা ইভেন্ট ম্যানেজ করে এমন একটি ফাংশন লেখো।

    যেমন, শুরু করতে, আপনি নিজের সোর্সে নিম্নলিখিত মতো একটি নো-অপ ফাংশন যোগ করতে পারেন:

    Node.js

    import {
      beforeUserCreated,
    } from "firebase-functions/v2/identity";
    
    export const beforecreated = beforeUserCreated((event) => {
      // TODO
      return;
    });
    

    Python

    @identity_fn.before_user_created()
    def created_noop(
        event: identity_fn.AuthBlockingEvent,
    ) -> identity_fn.BeforeCreateResponse | None:
        return
    

    উপরের উদাহরণে কাস্টম অথরাইজেশন লজিক প্রয়োগ করা হয়নি। আপনার ব্লকিং ফাংশন কীভাবে প্রয়োগ করবেন এবং নির্দিষ্ট উদাহরণের জন্য সাধারণ পরিস্থিতি সম্পর্কে জানতে নিম্নলিখিত বিভাগগুলি দেখুন।

  2. Firebase CLI ব্যবহার করে আপনার ফাংশন ডিপ্লয় করুন:

    firebase deploy --only functions
    

    প্রতিবার ফাংশন আপডেট করার সময় আপনাকে সেগুলি আবার ডেপ্লয় করতে হবে।

ব্যবহারকারী ও প্রসঙ্গ সংক্রান্ত তথ্য পাওয়া

ব্লকিং ইভেন্ট AuthBlockingEvent অবজেক্ট প্রদান করে যাতে ব্যবহারকারীর সাইন-ইন করা সংক্রান্ত তথ্য থাকে। কোনও অপারেশন চালিয়ে যেতে দেওয়া হবে কিনা তা নির্ধারণ করতে আপনার কোডে এইসব ভ্যালু ব্যবহার করুন।

অবজেক্টে নিম্নলিখিত প্রপার্টি থাকে:

নাম বিবরণ উদাহরণ
locale অ্যাপ্লিকেশনের লোকেল। আপনি ক্লায়েন্ট SDK ব্যবহার করে অথবা REST API-তে লোকেল হেডার পাস করার মাধ্যমে লোকেল সেট করতে পারবেন। fr বা sv-SE
ipAddress যে ডিভাইস থেকে ব্যবহারকারী রেজিস্ট্রেশন বা সাইন-ইন করছেন সেটির IP অ্যাড্রেস । 114.14.200.1
userAgent ব্লকিং ফাংশন ট্রিগার করা ব্যবহারকারীর এজেন্ট। Mozilla/5.0 (X11; Linux x86_64)
eventId ইভেন্টের অনন্য শনাক্তকারী। rWsyPtolplG2TBFoOkkgyg
eventType ইভেন্টের ধরন। এটি ইভেন্টের নাম সম্পর্কে তথ্য প্রদান করে, যেমন beforeSignIn বা beforeCreate এবং Google বা ইমেল/পাসওয়ার্ডের মতো ব্যবহৃত সংশ্লিষ্ট সাইন-ইন পদ্ধতি। providers/cloud.auth/eventTypes/user.beforeSignIn:password
authType সবসময় USER। USER
resource Firebase Authentication প্রোজেক্ট বা টেন্যান্ট। projects/project-id/tenants/tenant-id
timestamp ইভেন্ট ট্রিগার হওয়ার সময়, RFC 3339 স্ট্রিং হিসেবে ফর্ম্যাট করা হয়। Tue, 23 Jul 2019 21:10:57 GMT
additionalUserInfo ব্যবহারকারী সম্পর্কে তথ্য সহ একটি অবজেক্ট। AdditionalUserInfo
credential ব্যবহারকারীর ক্রেডেনশিয়াল সংক্রান্ত তথ্য সহ একটি অবজেক্ট। AuthCredential

রেজিস্ট্রেশন বা সাইন-ইন ব্লক করা

রেজিস্ট্রেশন বা সাইন-ইন করার চেষ্টা ব্লক করতে, আপনার ফাংশনে একটি HttpsError থ্রো করুন। যেমন:

Node.js

import { HttpsError } from "firebase-functions/v2/identity";

throw new HttpsError('invalid-argument');

Python

raise https_fn.HttpsError(
    code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT)

এছাড়াও, আপনি কাস্টম ত্রুটি মেসেজ নির্দিষ্ট করতে পারেন:

Node.js

throw new HttpsError('permission-denied', 'Unauthorized request origin!');

Python

raise https_fn.HttpsError(
    code=https_fn.FunctionsErrorCode.PERMISSION_DENIED,
    message="Unauthorized request origin!"
)

নিচের উদাহরণে দেখানো হয়েছে যে কীভাবে নির্দিষ্ট ডোমেনের মধ্যে নেই এমন ব্যবহারকারীদের আপনার অ্যাপে রেজিস্টার করা থেকে ব্লক করতে হয়:

Node.js

export const beforecreated = beforeUserCreated((event) => {
  const user = event.data;
  // (If the user is authenticating within a tenant context, the tenant ID can be determined from
  // user.tenantId or from event.resource, e.g. 'projects/project-id/tenant/tenant-id-1')

  // Only users of a specific domain can sign up.
  if (!user?.email?.includes('@acme.com')) {
    throw new HttpsError('invalid-argument', "Unauthorized email");
  }
});

Python

# Block account creation with any non-acme email address.
@identity_fn.before_user_created()
def validatenewuser(
    event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeCreateResponse | None:
    # User data passed in from the CloudEvent.
    user = event.data

    # Only users of a specific domain can sign up.
    if user.email is None or "@acme.com" not in user.email:
        # Return None so that Firebase Auth rejects the account creation.
        raise https_fn.HttpsError(
            code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT,
            message="Unauthorized email",
        )

আপনি ডিফল্ট বা কাস্টম মেসেজ যাই ব্যবহার করুন না কেন, Cloud Functions সমস্যার মেসেজটি র‍্যাপ করে এবং ক্লায়েন্টকে ইন্টার্নাল এরর হিসেবে রিটার্ন করে। যেমন:

Node.js

throw new HttpsError('invalid-argument', "Unauthorized email");

Python

# Only users of a specific domain can sign up.
if user.email is None or "@acme.com" not in user.email:
    # Return None so that Firebase Auth rejects the account creation.
    raise https_fn.HttpsError(
        code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT,
        message="Unauthorized email",
    )

আপনার অ্যাপের উচিত সমস্যাটি শনাক্ত করা এবং সেই অনুযায়ী ব্যবস্থা নেওয়া। যেমন:

জাভাস্ক্রিপ্ট

import { getAuth, createUserWithEmailAndPassword } from 'firebase/auth';

// Blocking functions can also be triggered in a multi-tenant context before user creation.
// firebase.auth().tenantId = 'tenant-id-1';
const auth = getAuth();
try {
  const result = await createUserWithEmailAndPassword(auth)
  const idTokenResult = await result.user.getIdTokenResult();
  console.log(idTokenResult.claim.admin);
} catch(error) {
  if (error.code !== 'auth/internal-error' && error.message.indexOf('Cloud Function') !== -1) {
      // Display error.
    } else {
      // Registration succeeds.
    }
}

ব্যবহারকারীকে পরিবর্তন করা

রেজিস্ট্রেশন বা সাইন-ইন করার চেষ্টা ব্লক না করে, আপনি অপারেশন চালিয়ে যাওয়ার অনুমতি দিতে পারেন, তবে User অবজেক্টটি পরিবর্তন করুন যা Firebase Authentication-এর ডেটাবেসে সেভ করা হয় এবং ক্লায়েন্টকে ফেরত দেওয়া হয়।

কোনও ব্যবহারকারীকে পরিবর্তন করতে, আপনার ইভেন্ট হ্যান্ডলার থেকে একটি অবজেক্ট রিটার্ন করুন যাতে পরিবর্তন করার জন্য ফিল্ড থাকে। আপনি নিম্নলিখিত ফিল্ড পরিবর্তন করতে পারবেন:

  • displayName
  • disabled
  • emailVerified
  • photoURL
  • customClaims
  • sessionClaims (শুধুমাত্র beforeUserSignedIn)

sessionClaims ছাড়া, সব পরিবর্তিত ফিল্ড Firebase Authentication-এর ডেটাবেসে সেভ করা হয়, যার অর্থ হল সেগুলি রেসপন্স টোকেনে অন্তর্ভুক্ত থাকে এবং ব্যবহারকারীর সেশন জুড়ে সেগুলি থেকে যায়।

নিম্নলিখিত উদাহরণ থেকে কীভাবে ডিফল্ট ডিসপ্লে নাম সেট করতে হয় তা জানুন:

Node.js

export const beforecreated = beforeUserCreated((event) => {
  return {
    // If no display name is provided, set it to "Guest".
    displayName: event.data.displayName || 'Guest'
  };
});

Python

@identity_fn.before_user_created()
def setdefaultname(
    event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeCreateResponse | None:
    return identity_fn.BeforeCreateResponse(
        # If no display name is provided, set it to "Guest".
        display_name=event.data.display_name if event.data.display_name is not None else "Guest"
    )

আপনি beforeUserCreated ও beforeUserSignedIn, দুটির জন্যই ইভেন্ট হ্যান্ডলার রেজিস্টার করলে, মনে রাখবেন যে beforeUserCreated-এর পরে beforeUserSignedIn এক্সিকিউট হয়। beforeUserCreated-এ আপডেট করা ব্যবহারকারীর ফিল্ড beforeUserSignedIn-এ দেখা যায়। আপনি যদি দুটি ইভেন্ট হ্যান্ডলারেই sessionClaims ছাড়া অন্য কোনও ফিল্ড সেট করেন, তাহলে beforeUserSignedIn-এ সেট করা ভ্যালু beforeUserCreated-এ সেট করা ভ্যালুকে ওভাররাইট করে দেয়। শুধুমাত্র sessionClaims-এর জন্য, সেগুলি বর্তমান সেশনের টোকেন দাবিতে প্রোপাগেট করা হয়, তবে সেগুলি ডাটাবেসে সেভ বা স্টোর করা হয় না।

যেমন, কোনও sessionClaims সেট করা থাকলে, beforeUserSignedIn সেগুলি যেকোনও beforeUserCreated দাবি সহ ফেরত দেবে এবং সেগুলি মার্জ করা হবে। সেগুলি মার্জ করা হলে, যদি sessionClaims কী, customClaims-এর কোনও কী-এর সাথে ম্যাচ করে, তাহলে ম্যাচ করা customClaims, sessionClaims কী-এর মাধ্যমে টোকেন দাবিগুলিতে ওভাররাইট করা হবে। তবে, ওভাররাইট করা customClaims কীটি ভবিষ্যতের অনুরোধের জন্য ডেটাবেসে সেভ করা থাকবে।

OAuth ক্রেডেনশিয়াল ও ডেটা যা কাজ করে

আপনি বিভিন্ন পরিচয় প্রদানকারীর থেকে ব্লকিং ফাংশনে OAuth ক্রেডেনশিয়াল ও ডেটা পাস করতে পারবেন। নিচের সারণীতে প্রতিটি পরিচয় প্রদানকারীর জন্য কোন কোন ক্রেডেনশিয়াল ও ডেটা কাজ করে তা দেখানো হয়েছে:

পরিচয় প্রদানকারী ID টোকেন অ্যাক্সেস টোকেন মেয়াদ শেষ হওয়ার সময় টোকেন সিক্রেট রিফ্রেশ টোকেন সাইন-ইন দাবি
Google হ্যাঁ হ্যাঁ হ্যাঁ না হ্যাঁ না
Facebook না হ্যাঁ হ্যাঁ না না না
Twitter না হ্যাঁ না হ্যাঁ না না
GitHub না হ্যাঁ না না না না
Microsoft হ্যাঁ হ্যাঁ হ্যাঁ না হ্যাঁ না
LinkedIn না হ্যাঁ হ্যাঁ না না না
Yahoo হ্যাঁ হ্যাঁ হ্যাঁ না হ্যাঁ না
Apple হ্যাঁ হ্যাঁ হ্যাঁ না হ্যাঁ না
SAML না না না না না হ্যাঁ
OIDC হ্যাঁ হ্যাঁ হ্যাঁ না হ্যাঁ হ্যাঁ

OAuth টোকেন

ব্লকিং ফাংশনে ID টোকেন, অ্যাক্সেস টোকেন বা রিফ্রেশ টোকেন ব্যবহার করতে, আপনাকে প্রথমে Firebase কনসোলের ব্লকিং ফাংশন পৃষ্ঠায় চেকবক্স বেছে নিতে হবে (নিরাপত্তা > অনুমোদন > সেটিংস ট্যাব বিকল্পে যান)।

আইডি টোকেন বা অ্যাক্সেস টোকেনের মতো OAuth ক্রেডেনশিয়াল দিয়ে সরাসরি সাইন-ইন করলে কোনও পরিচয় প্রদানকারী রিফ্রেশ টোকেন ফেরত দেবে না। এই পরিস্থিতিতে, একই ক্লায়েন্ট-সাইড OAuth ক্রেডেনশিয়াল ব্লকিং ফাংশনে পাস করা হবে।

নিচের বিভাগে প্রতিটি পরিচয় প্রদানকারীর ধরন এবং সেগুলির সাথে কাজ করে এমন ক্রেডেনশিয়াল ও ডেটা সম্পর্কে বর্ণনা করা হয়েছে।

জেনারেটিক OIDC প্রদানকারী

কোনও ব্যবহারকারী জেনেরিক OIDC প্রদানকারীর মাধ্যমে সাইন-ইন করলে, নিম্নলিখিত ক্রেডেনশিয়াল পাস করা হবে:

  • আইডি টোকেন: id_token ফ্লো বেছে নেওয়া হলে প্রদান করা হয়।
  • অ্যাক্সেস টোকেন: কোড ফ্লো বেছে নেওয়া হলে এটি প্রদান করা হয়। মনে রাখবেন, কোড ফ্লো বর্তমানে শুধুমাত্র REST API-এর মাধ্যমে কাজ করে।
  • রিফ্রেশ টোকেন: offline_access স্কোপ বেছে নেওয়া হলে এটি প্রদান করা হয়।

উদাহরণ:

const provider = new firebase.auth.OAuthProvider('oidc.my-provider');
provider.addScope('offline_access');
firebase.auth().signInWithPopup(provider);

Google

কোনও ব্যবহারকারী Google-এর মাধ্যমে সাইন-ইন করলে, নিম্নলিখিত ক্রেডেনশিয়াল পাস করা হবে:

  • আইডি টোকেন
  • অ্যাক্সেস টোকেন
  • রিফ্রেশ টোকেন: নিম্নলিখিত কাস্টম প্যারামিটার অনুরোধ করা হলেই শুধু প্রদান করা হয়:
    • access_type=offline
    • prompt=consent, ব্যবহারকারী আগে সম্মতি দিয়ে থাকলে এবং কোনও নতুন স্কোপের অনুরোধ না করা হলে

উদাহরণ:

import { getAuth, signInWithPopup, GoogleAuthProvider } from 'firebase/auth';

const auth = getAuth();
const provider = new GoogleAuthProvider();
provider.setCustomParameters({
  'access_type': 'offline',
  'prompt': 'consent'
});
signInWithPopup(auth, provider);

Google রিফ্রেশ টোকেন সম্পর্কে আরও জানুন।

Facebook

কোনও ব্যবহারকারী Facebook-এর মাধ্যমে সাইন-ইন করলে, নিম্নলিখিত ক্রেডেনশিয়াল পাস করা হবে:

  • অ্যাক্সেস টোকেন: একটি অ্যাক্সেস টোকেন ফেরত দেওয়া হয় যা অন্য অ্যাক্সেস টোকেনের সাথে বিনিময় করা যায়। Facebook-এ কাজ করে এমন বিভিন্ন ধরনের অ্যাক্সেস টোকেন এবং কীভাবে আপনি সেগুলিকে দীর্ঘমেয়াদী টোকেন-এর সাথে অদল-বদল করতে পারবেন সেই সম্পর্কে আরও জানুন।

GitHub

কোনও ব্যবহারকারী GitHub-এর মাধ্যমে সাইন-ইন করলে, নিম্নলিখিত ক্রেডেনশিয়াল পাস করা হবে:

  • অ্যাক্সেস টোকেন: বাতিল না করা পর্যন্ত মেয়াদ শেষ হয় না।

Microsoft

কোনও ব্যবহারকারী Microsoft-এর মাধ্যমে সাইন-ইন করলে, নিম্নলিখিত ক্রেডেনশিয়াল পাস করা হবে:

  • আইডি টোকেন
  • অ্যাক্সেস টোকেন
  • রিফ্রেশ টোকেন: offline_access স্কোপ বেছে নেওয়া হলে, ব্লকিং ফাংশনে পাস করা হয়।

উদাহরণ:

import { getAuth, signInWithPopup, OAuthProvider } from 'firebase/auth';

const auth = getAuth();
const provider = new OAuthProvider('microsoft.com');
provider.addScope('offline_access');
signInWithPopup(auth, provider);

Yahoo

কোনও ব্যবহারকারী Yahoo-এর মাধ্যমে সাইন-ইন করলে, কোনও কাস্টম প্যারামিটার বা স্কোপ ছাড়াই নিম্নলিখিত ক্রেডেনশিয়াল পাস করা হবে:

  • আইডি টোকেন
  • অ্যাক্সেস টোকেন
  • রিফ্রেশ টোকেন

LinkedIn

কোনও ব্যবহারকারী LinkedIn-এর মাধ্যমে সাইন-ইন করলে, নিম্নলিখিত ক্রেডেনশিয়াল পাস করা হবে:

  • অ্যাক্সেস টোকেন

Apple

কোনও ব্যবহারকারী Apple-এর মাধ্যমে সাইন-ইন করলে, নিম্নলিখিত ক্রেডেনশিয়াল কোনও কাস্টম প্যারামিটার বা স্কোপ ছাড়াই পাস করা হবে:

  • আইডি টোকেন
  • অ্যাক্সেস টোকেন
  • রিফ্রেশ টোকেন

সাধারণ পরিস্থিতি

ফাংশন ব্লক করার কিছু সাধারণ ব্যবহারের উদাহরণ নিচে দেওয়া হল:

শুধুমাত্র নির্দিষ্ট ডোমেন থেকে রেজিস্ট্রেশনের অনুমতি দেওয়া

নিচের উদাহরণে দেখানো হয়েছে যে কীভাবে example.com ডোমেনের অংশ নয় এমন ব্যবহারকারীদের আপনার অ্যাপে রেজিস্টার করা থেকে আটকানো যায়:

Node.js

export const beforecreated = beforeUserCreated((event) => {
  const user = event.data;
  if (!user?.email?.includes('@example.com')) {
    throw new HttpsError(
      'invalid-argument', 'Unauthorized email');
  }
});

Python

 @identity_fn.before_user_created()
   def validatenewuser(
       event: identity_fn.AuthBlockingEvent,
   ) -> identity_fn.BeforeCreateResponse | None:
       # User data passed in from the CloudEvent.
       user = event.data

       # Only users of a specific domain can sign up.
       if user.email is None or "@example.com" not in user.email:
           # Return None so that Firebase Auth rejects the account creation.
           raise https_fn.HttpsError(
               code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT,
               message="Unauthorized email",
           )

যাচাই না করা ইমেল আইডি সহ ব্যবহারকারীদের রেজিস্টার করা থেকে ব্লক করা

নিচের উদাহরণে দেখানো হয়েছে যে কীভাবে যাচাই না করা ইমেল আইডি সহ ব্যবহারকারীদের আপনার অ্যাপে রেজিস্টার করা থেকে আটকানো যায়:

Node.js

export const beforecreated = beforeUserCreated((event) => {
  const user = event.data;
  if (user.email && !user.emailVerified) {
    throw new HttpsError(
      'invalid-argument', 'Unverified email');
  }
});

Python

@identity_fn.before_user_created()
def requireverified(
    event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeCreateResponse | None:
    if event.data.email is not None and not event.data.email_verified:
        raise https_fn.HttpsError(
            code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT,
            message="You must register using a trusted provider.",
        )

নির্দিষ্ট কিছু পরিচয় প্রদানকারীর ইমেলকে যাচাই করা হিসেবে বিবেচনা করা

নিচের উদাহরণে দেখানো হয়েছে যে কীভাবে নির্দিষ্ট পরিচয় প্রদানকারীর থেকে পাওয়া ব্যবহারকারীর ইমেলকে যাচাই করা হিসেবে বিবেচনা করতে হয়:

Node.js

export const beforecreated = beforeUserCreated((event) => {
  const user = event.data;
  if (user.email && !user.emailVerified && event.eventType.includes(':facebook.com')) {
    return {
      emailVerified: true,
    };
  }
});

Python

@identity_fn.before_user_created()
def markverified(
    event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeCreateResponse | None:
    if event.data.email is not None and "@facebook.com" in event.data.email:
        return identity_fn.BeforeSignInResponse(email_verified=True)

নির্দিষ্ট IP অ্যাড্রেস থেকে সাইন-ইন ব্লক করা

নিচের উদাহরণে দেখানো হয়েছে কীভাবে নির্দিষ্ট IP অ্যাড্রেস রেঞ্জ থেকে সাইন-ইন ব্লক করতে হয়:

Node.js

export const beforesignedin = beforeUserSignedIn((event) => {
  if (isSuspiciousIpAddress(event.ipAddress)) {
    throw new HttpsError(
      'permission-denied', 'Unauthorized access!');
  }
});

Python

@identity_fn.before_user_signed_in()
def ipban(
    event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeSignInResponse | None:
    if is_suspicious(event.ip_address):
        raise https_fn.HttpsError(
            code=https_fn.FunctionsErrorCode.PERMISSION_DENIED, message="IP banned."
        )

কাস্টম ও সেশন দাবি সেট করা

কাস্টম ও সেশন দাবি কীভাবে সেট করতে হয় তা নিম্নলিখিত উদাহরণ থেকে জানতে পারবেন:

Node.js

export const beforecreated = beforeUserCreated((event) => {
    if (event.credential &&
        event.credential.claims &&
        event.credential.providerId === "saml.my-provider-id") {
        return {
            // Employee ID does not change so save in persistent claims (stored in
            // Auth DB).
            customClaims: {
                eid: event.credential.claims.employeeid,
            },
        };
    }
});

export const beforesignin = beforeUserSignedIn((event) => {
    if (event.credential &&
        event.credential.claims &&
        event.credential.providerId === "saml.my-provider-id") {
        return {
            // Copy role and groups to token claims. These will not be persisted.
            sessionClaims: {
                role: event.credential.claims.role,
                groups: event.credential.claims.groups,
            },
        };
    }
});

Python

@identity_fn.before_user_created()
def setemployeeid(
    event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeCreateResponse | None:
    if (
        event.credential is not None
        and event.credential.claims is not None
        and event.credential.provider_id == "saml.my-provider-id"
    ):
        return identity_fn.BeforeCreateResponse(
            custom_claims={"eid": event.credential.claims["employeeid"]}
        )


@identity_fn.before_user_signed_in()
def copyclaimstosession(
    event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeSignInResponse | None:
    if (
        event.credential is not None
        and event.credential.claims is not None
        and event.credential.provider_id == "saml.my-provider-id"
    ):
        return identity_fn.BeforeSignInResponse(
            session_claims={
                "role": event.credential.claims["role"],
                "groups": event.credential.claims["groups"],
            }
        )

সন্দেহজনক অ্যাক্টিভিটি মনিটর করতে IP অ্যাড্রেস ট্র্যাক করা

ব্যবহারকারী যে IP অ্যাড্রেস থেকে সাইন-ইন করেছেন সেটি ট্র্যাক করে এবং পরবর্তী অনুরোধের IP অ্যাড্রেসের সাথে তুলনা করে আপনি টোকেন চুরি হওয়া আটকাতে পারেন। অনুরোধটি সন্দেহজনক মনে হলে — যেমন, IP অ্যাড্রেসগুলি আলাদা আলাদা ভৌগোলিক অঞ্চল থেকে এসেছে — আপনি ব্যবহারকারীকে আবার সাইন-ইন করতে বলতে পারেন।

  1. ব্যবহারকারী যে IP অ্যাড্রেস দিয়ে সাইন-ইন করেন সেটি ট্র্যাক করতে সেশন দাবি ব্যবহার করুন:

    Node.js

    export const beforesignedin = beforeUserSignedIn((event) => {
      return {
        sessionClaims: {
          signInIpAddress: event.ipAddress,
        },
      };
    });
    

    Python

    @identity_fn.before_user_signed_in()
    def logip(
        event: identity_fn.AuthBlockingEvent,
    ) -> identity_fn.BeforeSignInResponse | None:
        return identity_fn.BeforeSignInResponse(session_claims={"signInIpAddress": event.ip_address})
    
  2. কোনও ব্যবহারকারী যখন এমন রিসোর্স অ্যাক্সেস করার চেষ্টা করেন যার জন্য যাচাইকরণ প্রয়োজন Firebase Authentication, তখন অনুরোধে থাকা IP অ্যাড্রেসটি সাইন-ইন করার জন্য ব্যবহৃত IP-র সাথে তুলনা করুন:

    Node.js

    app.post('/getRestrictedData', (req, res) => {
      // Get the ID token passed.
      const idToken = req.body.idToken;
      // Verify the ID token, check if revoked and decode its payload.
      admin.auth().verifyIdToken(idToken, true).then((claims) => {
        // Get request IP address
        const requestIpAddress = req.connection.remoteAddress;
        // Get sign-in IP address.
        const signInIpAddress = claims.signInIpAddress;
        // Check if the request IP address origin is suspicious relative to
        // the session IP addresses. The current request timestamp and the
        // auth_time of the ID token can provide additional signals of abuse,
        // especially if the IP address suddenly changed. If there was a sudden
        // geographical change in a short period of time, then it will give
        // stronger signals of possible abuse.
        if (!isSuspiciousIpAddressChange(signInIpAddress, requestIpAddress)) {
          // Suspicious IP address change. Require re-authentication.
          // You can also revoke all user sessions by calling:
          // admin.auth().revokeRefreshTokens(claims.sub).
          res.status(401).send({error: 'Unauthorized access. Please login again!'});
        } else {
          // Access is valid. Try to return data.
          getData(claims).then(data => {
            res.end(JSON.stringify(data);
          }, error => {
            res.status(500).send({ error: 'Server error!' })
          });
        }
      });
    });
    

    Python

    from firebase_admin import auth, initialize_app
    import flask
    
    initialize_app()
    flask_app = flask.Flask(__name__)
    
    @flask_app.post()
    def get_restricted_data(req: flask.Request):
        # Get the ID token passed.
        id_token = req.json().get("idToken")
    
        # Verify the ID token, check if revoked, and decode its payload.
        try:
            claims = auth.verify_id_token(id_token, check_revoked=True)
        except:
            return flask.Response(status=500)
    
        # Get request IP address.
        request_ip = req.remote_addr
    
        # Get sign-in IP address.
        signin_ip = claims["signInIpAddress"]
    
        # Check if the request IP address origin is suspicious relative to
        # the session IP addresses. The current request timestamp and the
        # auth_time of the ID token can provide additional signals of abuse,
        # especially if the IP address suddenly changed. If there was a sudden
        # geographical change in a short period of time, then it will give
        # stronger signals of possible abuse.
        if is_suspicious_change(signin_ip, request_ip):
            # Suspicious IP address change. Require re-authentication.
            # You can also revoke all user sessions by calling:
            #   auth.revoke_refresh_tokens(claims["sub"])
            return flask.Response(status=401,
                                  response="Unauthorized access. Sign in again!")
        else:
            # Access is valid. Try to return data.
            return data_from_claims(claims)
    

ব্যবহারকারীর ফটো স্ক্রিনিং করা

ব্যবহারকারীর প্রোফাইল ফটো কীভাবে স্যানিটাইজ করতে হয় তা নিম্নলিখিত উদাহরণ থেকে দেখুন:

Node.js

export const beforecreated = beforeUserCreated((event) => {
  const user = event.data;
  if (user.photoURL) {
    return isPhotoAppropriate(user.photoURL)
      .then((status) => {
        if (!status) {
          // Sanitize inappropriate photos by replacing them with guest photos.
          // Users could also be blocked from sign-up, disabled, etc.
          return {
            photoURL: PLACEHOLDER_GUEST_PHOTO_URL,
          };
        }
      });
});

Python

@identity_fn.before_user_created()
def sanitizeprofilephoto(
    event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeCreateResponse | None:
    if event.data.photo_url is not None:
        score = analyze_photo_with_ml(event.data.photo_url)
        if score > THRESHOLD:
            return identity_fn.BeforeCreateResponse(photo_url=PLACEHOLDER_URL)

কীভাবে ছবি শনাক্ত ও স্যানিটাইজ করতে হয় সেই সম্পর্কে আরও জানতে, Cloud Vision ডকুমেন্টেশন দেখুন।

ব্যবহারকারীর পরিচয় প্রদানকারীর OAuth ক্রেডেনশিয়াল অ্যাক্সেস করা

নিচের উদাহরণে দেখানো হয়েছে যে Google-এর মাধ্যমে সাইন-ইন করা কোনও ব্যবহারকারীর জন্য কীভাবে রিফ্রেশ টোকেন পেতে হয় এবং Google Calendar API কল করার জন্য এটি ব্যবহার করতে হয়। অফলাইন অ্যাক্সেসের জন্য রিফ্রেশ টোকেন সেভ করা হয়।

Node.js

const {OAuth2Client} = require('google-auth-library');
const {google} = require('googleapis');
// ...
// Initialize Google OAuth client.
const keys = require('./oauth2.keys.json');
const oAuth2Client = new OAuth2Client(
  keys.web.client_id,
  keys.web.client_secret
);

export const beforecreated = beforeUserCreated((event) => {
  const user = event.data;
  if (event.credential &&
      event.credential.providerId === 'google.com') {
    // Store the refresh token for later offline use.
    // These will only be returned if refresh tokens credentials are included
    // (enabled by Cloud console).
    return saveUserRefreshToken(
        user.uid,
        event.credential.refreshToken,
        'google.com'
      )
      .then(() => {
        // Blocking the function is not required. The function can resolve while
        // this operation continues to run in the background.
        return new Promise((resolve, reject) => {
          // For this operation to succeed, the appropriate OAuth scope should be requested
          // on sign in with Google, client-side. In this case:
          // https://www.googleapis.com/auth/calendar
          // You can check granted_scopes from within:
          // event.additionalUserInfo.profile.granted_scopes (space joined list of scopes).

          // Set access token/refresh token.
          oAuth2Client.setCredentials({
            access_token: event.credential.accessToken,
            refresh_token: event.credential.refreshToken,
          });
          const calendar = google.calendar('v3');
          // Setup Onboarding event on user's calendar.
          const event = {/** ... */};
          calendar.events.insert({
            auth: oauth2client,
            calendarId: 'primary',
            resource: event,
          }, (err, event) => {
            // Do not fail. This is a best effort approach.
            resolve();
          });
      });
    })
  }
});

Python

@identity_fn.before_user_created()
def savegoogletoken(
    event: identity_fn.AuthBlockingEvent,
) -> identity_fn.BeforeCreateResponse | None:
    """During sign-up, save the Google OAuth2 access token and queue up a task
    to schedule an onboarding session on the user's Google Calendar.

    You will only get an access token if you enabled it in your project's blocking
    functions settings in the Firebase console:

    https://console.firebase.google.com/project/_/authentication/settings
    """
    if event.credential is not None and event.credential.provider_id == "google.com":
        print(f"Signed in with {event.credential.provider_id}. Saving access token.")

        firestore_client: google.cloud.firestore.Client = firestore.client()
        doc_ref = firestore_client.collection("user_info").document(event.data.uid)
        doc_ref.set({"calendar_access_token": event.credential.access_token}, merge=True)

        tasks_client = google.cloud.tasks_v2.CloudTasksClient()
        task_queue = tasks_client.queue_path(
            params.PROJECT_ID.value, options.SupportedRegion.US_CENTRAL1.value, "scheduleonboarding"
        )
        target_uri = get_function_url("scheduleonboarding")
        calendar_task = google.cloud.tasks_v2.Task(
            http_request={
                "http_method": google.cloud.tasks_v2.HttpMethod.POST,
                "url": target_uri,
                "headers": {"Content-type": "application/json"},
                "body": json.dumps({"data": {"uid": event.data.uid}}).encode(),
            },
            schedule_time=datetime.now() + timedelta(minutes=1),
        )
        tasks_client.create_task(parent=task_queue, task=calendar_task)

ব্যবহারকারীর অপারেশনের জন্য reCAPTCHA Enterprise-এর সিদ্ধান্ত ওভাররাইড করা

সাপোর্ট করা ব্যবহারকারীর ফ্লোয়ের জন্য কীভাবে reCAPTCHA Enterprise-এর সিদ্ধান্ত ওভাররাইড করতে হয় তা নিম্নলিখিত উদাহরণ থেকে দেখুন।

Firebase Authentication-এর সাথে reCAPTCHA Enterprise ইন্টিগ্রেট করা সম্পর্কে আরও জানতে reCAPTCHA Enterprise চালু করুন দেখুন।

কাস্টম ফ্যাক্টরের উপর ভিত্তি করে ফ্লোকে অনুমতি দিতে বা ব্লক করতে, ব্লকিং ফাংশন ব্যবহার করা যেতে পারে। এর ফলে, reCAPTCHA Enterprise-এর দেওয়া ফলাফল ওভাররাইড করা হয়।

Node.js

const { beforeSmsSent } = require("firebase-functions/v2/identity");
exports.beforesmssentv2 = beforeSmsSent((event) => {
 if (
   event.smsType === "SIGN_IN_OR_SIGN_UP" &&
   event.additionalUserInfo.phoneNumber.includes('+91')
 ) {
   return {
     recaptchaActionOverride: "ALLOW",
   };
 }

 // Allow users to sign in with recaptcha score greater than 0.5
 if (event.additionalUserInfo.recaptchaScore > 0.5) {
   return {
     recaptchaActionOverride: 'ALLOW',
   };
 }

 // Block all others.
 return  {
   recaptchaActionOverride: 'BLOCK',
 }
});