Firebase SQL Connect নিম্নলিখিত উপায়ে শক্তিশালী ক্লায়েন্ট-সাইড নিরাপত্তা প্রদান করে:
- মোবাইল এবং ওয়েব ক্লায়েন্ট অনুমোদন
- স্বতন্ত্র কোয়েরি- এবং মিউটেশন-স্তরের অনুমোদন নিয়ন্ত্রণ
- Firebase App Check মাধ্যমে অ্যাপের সত্যায়ন।
SQL Connect নিম্নলিখিত উপায়ে এই নিরাপত্তা আরও প্রসারিত করে:
- সার্ভার-সাইড অনুমোদন
- IAM-এর মাধ্যমে Firebase প্রজেক্ট এবং Cloud SQL ব্যবহারকারীর নিরাপত্তা।
ক্লায়েন্টের কোয়েরি এবং পরিবর্তন অনুমোদন করুন
SQL Connect Firebase Authentication সাথে সম্পূর্ণরূপে সমন্বিত, তাই আপনার ডেটা অ্যাক্সেসকারী ব্যবহারকারীদের (অথরাইজেশন) অ্যাক্সেসের অনুমতি দেওয়ার ডিজাইনে আপনি তাদের সম্পর্কিত বিস্তারিত ডেটা (অথেন্টিকেশন) ব্যবহার করতে পারেন।
SQL Connect কোয়েরি এবং মিউটেশনের জন্য একটি @auth ডিরেক্টিভ প্রদান করে, যা আপনাকে অপারেশনটি অনুমোদন করার জন্য প্রয়োজনীয় অথেনটিকেশনের স্তর নির্ধারণ করতে দেয়। এই নির্দেশিকাটি উদাহরণসহ @auth ডিরেক্টিভটির সাথে পরিচয় করিয়ে দেয় ।
এছাড়াও, SQL Connect মিউটেশনের মধ্যে এমবেড করা কোয়েরি চালানো সমর্থন করে, তাই আপনি আপনার ডাটাবেসে সংরক্ষিত অতিরিক্ত অনুমোদনের মানদণ্ড পুনরুদ্ধার করতে পারেন এবং সেই মানদণ্ডগুলো @check নির্দেশিকায় ব্যবহার করে সিদ্ধান্ত নিতে পারেন যে এনক্লোজিং মিউটেশনগুলো অনুমোদিত কিনা। এই অনুমোদনের ক্ষেত্রে, @redact নির্দেশিকাটি আপনাকে নিয়ন্ত্রণ করতে দেয় যে কোয়েরির ফলাফল ওয়্যার প্রোটোকলে ক্লায়েন্টদের কাছে ফেরত পাঠানো হবে কিনা এবং জেনারেটেড SDK-গুলোতে এমবেড করা কোয়েরিটি বাদ দেওয়া হবে কিনা। উদাহরণসহ এই নির্দেশিকাগুলোর পরিচিতি খুঁজুন।
@auth নির্দেশিকাটি বুঝুন
আপনি @auth ডিরেক্টিভটিকে কয়েকটি পূর্বনির্ধারিত অ্যাক্সেস লেভেলের যেকোনো একটি অনুসরণ করার জন্য প্যারামিটারাইজ করতে পারেন, যা অনেক সাধারণ অ্যাক্সেস পরিস্থিতিকে অন্তর্ভুক্ত করে। এই লেভেলগুলো PUBLIC (যা কোনো প্রকার প্রমাণীকরণ ছাড়াই সকল ক্লায়েন্টকে কোয়েরি এবং মিউটেশন করার অনুমতি দেয়) থেকে NO_ACCESS (যা Firebase Admin SDK ব্যবহার করে বিশেষাধিকারপ্রাপ্ত সার্ভার পরিবেশের বাইরে কোয়েরি এবং মিউটেশন করার অনুমতি দেয় না) পর্যন্ত বিস্তৃত। এই প্রতিটি লেভেল Firebase Authentication দ্বারা প্রদত্ত প্রমাণীকরণ প্রবাহের সাথে সম্পর্কিত।
| স্তর | সংজ্ঞা |
|---|---|
PUBLIC | এই অপারেশনটি প্রমাণীকরণ সহ বা প্রমাণীকরণ ছাড়াই যে কেউ সম্পাদন করতে পারে। |
USER_ANON | Firebase Authentication ব্যবহার করে বেনামে লগ ইন করা ব্যবহারকারীসহ যেকোনো শনাক্তকৃত ব্যবহারকারী কোয়েরি বা মিউটেশনটি সম্পাদন করার জন্য অনুমোদিত। |
USER | বেনামী সাইন-ইন ব্যবহারকারী ব্যতীত, Firebase Authentication দিয়ে লগ ইন করা যেকোনো ব্যবহারকারী কোয়েরি বা মিউটেশন সম্পাদন করার জন্য অনুমোদিত। |
USER_EMAIL_VERIFIED | যে কোনো ব্যবহারকারী যিনি একটি যাচাইকৃত ইমেল ঠিকানা দিয়ে Firebase Authentication ব্যবহার করে লগ ইন করেছেন, তিনি কোয়েরি বা মিউটেশনটি সম্পাদন করার জন্য অনুমোদিত। |
NO_ACCESS | এই অপারেশনটি অ্যাডমিন SDK কনটেক্সটের বাইরে চালানো যাবে না। |
এই পূর্বনির্ধারিত অ্যাক্সেস লেভেলগুলোকে ভিত্তি করে, আপনি @auth ডিরেক্টিভে where ফিল্টার এবং সার্ভারে ইভ্যালুয়েট করা কমন এক্সপ্রেশন ল্যাঙ্গুয়েজ (CEL) এক্সপ্রেশন ব্যবহার করে জটিল ও শক্তিশালী অথরাইজেশন চেক সংজ্ঞায়িত করতে পারেন।
সাধারণ অনুমোদন পরিস্থিতিগুলো বাস্তবায়ন করতে @auth নির্দেশিকাটি ব্যবহার করুন।
পূর্বনির্ধারিত প্রবেশাধিকার স্তরগুলো অনুমোদনের প্রাথমিক ধাপ ।
USER অ্যাক্সেস লেভেল হলো শুরু করার জন্য সবচেয়ে বহুল ব্যবহৃত প্রাথমিক স্তর।
সম্পূর্ণ সুরক্ষিত অ্যাক্সেস USER লেভেলের উপর ভিত্তি করে তৈরি হবে, যার সাথে থাকবে ফিল্টার এবং এক্সপ্রেশন যা ব্যবহারকারীর অ্যাট্রিবিউট, রিসোর্স অ্যাট্রিবিউট, রোল এবং অন্যান্য বিষয় যাচাই করবে। USER_ANON এবং USER_EMAIL_VERIFIED লেভেলগুলো হলো USER লেভেলেরই ভিন্ন রূপ।
এক্সপ্রেশন সিনট্যাক্স আপনাকে একটি auth অবজেক্ট ব্যবহার করে ডেটা মূল্যায়ন করতে দেয়, যা অপারেশনগুলির সাথে প্রেরিত প্রমাণীকরণ ডেটা উপস্থাপন করে; এর মধ্যে অথ টোকেনে থাকা স্ট্যান্ডার্ড ডেটা এবং টোকেনে থাকা কাস্টম ডেটা উভয়ই অন্তর্ভুক্ত। auth অবজেক্টে উপলব্ধ ফিল্ডগুলির তালিকার জন্য, রেফারেন্স বিভাগটি দেখুন।
অবশ্যই এমন কিছু ব্যবহারের ক্ষেত্র আছে যেখানে শুরু করার জন্য PUBLIC ই সঠিক অ্যাক্সেস লেভেল। তবে, অ্যাক্সেস লেভেল সবসময়ই একটি সূচনা বিন্দু, এবং শক্তিশালী নিরাপত্তার জন্য অতিরিক্ত ফিল্টার ও এক্সপ্রেশনের প্রয়োজন হয়।
এই নির্দেশিকায় এখন USER এবং PUBLIC উপর ভিত্তি করে কীভাবে নির্মাণ করা যায় তার উদাহরণ দেওয়া হলো।
একটি অনুপ্রেরণামূলক উদাহরণ
নিম্নলিখিত সেরা অনুশীলনের উদাহরণগুলি একটি ব্লগিং প্ল্যাটফর্মের জন্য নিম্নলিখিত স্কিমাটিকে নির্দেশ করে, যেখানে নির্দিষ্ট কিছু কন্টেন্ট একটি পেমেন্ট প্ল্যানের আড়ালে লক করা থাকে।
এই ধরনের একটি প্ল্যাটফর্ম সম্ভবত Users এবং Posts আদলে তৈরি হবে।
type User @table(key: "uid") {
uid: String!
name: String
birthday: Date
createdAt: Timestamp! @default(expr: "request.time")
}
type Post @table {
author: User!
text: String!
# "one of 'draft', 'public', or 'pro'"
visibility: String! @default(value: "draft")
# "the time at which the post should be considered published. defaults to
# immediately"
publishedAt: Timestamp! @default(expr: "request.time")
createdAt: Timestamp! @default(expr: "request.time")
updatedAt: Timestamp! @default(expr: "request.time")
}
ব্যবহারকারীর মালিকানাধীন সম্পদ
ফায়ারবেস পরামর্শ দেয় যে আপনি এমন ফিল্টার এবং এক্সপ্রেশন লিখুন যা কোনো রিসোর্সের উপর ব্যবহারকারীর মালিকানা যাচাই করে, যেমন Posts মালিকানার ক্ষেত্রে।
নিম্নলিখিত উদাহরণগুলিতে, এক্সপ্রেশন ব্যবহার করে অথ টোকেন থেকে ডেটা পড়া এবং তুলনা করা হয়। প্রচলিত রীতি হলো, অথেন্টিকেশন টোকেনে পাঠানো auth.uid (ইউজার আইডি)-এর সাথে সংরক্ষিত authorUid তুলনা করার জন্য where: {authorUid: {eq_expr: "auth.uid"}} মতো এক্সপ্রেশন ব্যবহার করা।
তৈরি করুন
এই অনুমোদন প্রক্রিয়াটি শুরু হয় প্রতিটি নতুন Post অথ টোকেন থেকে auth.uid authorUid ফিল্ড হিসেবে যোগ করার মাধ্যমে, যাতে পরবর্তী অনুমোদন পরীক্ষাগুলোতে তুলনা করা যায়।
# Create a new post as the current user
mutation CreatePost($text: String!, $visibility: String) @auth(level: USER) {
post_insert(data: {
# set the author's uid to the current user uid
authorUid_expr: "auth.uid"
text: $text
visibility: $visibility
})
}
আপডেট
যখন কোনো ক্লায়েন্ট একটি Post আপডেট করার চেষ্টা করে, তখন আপনি প্রদত্ত auth.uid সংরক্ষিত authorUid সাথে মিলিয়ে দেখতে পারেন।
# Update one of the current user's posts
mutation UpdatePost($id: UUID!, $text: String, $visibility: String) @auth(level:USER) {
post_update(
# only update posts whose author is the current user
first: { where: {
id: {eq: $id}
authorUid: {eq_expr: "auth.uid"}
}}
data: {
text: $text
visibility: $visibility
# insert the current server time for updatedAt
updatedAt_expr: "request.time"
}
)
}
মুছে ফেলুন
মুছে ফেলার কার্যক্রম অনুমোদন করতেও একই কৌশল ব্যবহার করা হয়।
# Delete one of the current user's posts
mutation DeletePost($id: UUID!) @auth(level: USER) {
post_delete(
# only delete posts whose author is the current user
first: { where: {
id: {eq: $id}
authorUid: {eq_expr: "auth.uid"}
}}
)
}
# Common display information for a post
fragment DisplayPost on Post {
id, text, createdAt, updatedAt
author { uid, name }
}
তালিকা
# List all posts belonging to the current user
query ListMyPosts @auth(level: USER) {
posts(where: {
userUid: {eq_expr: "auth.uid"}
}) {
# See the fragment above
...DisplayPost
# also show visibility since it is user-controlled
visibility
}
}
পান
# Get a post only if it belongs to the current user
query GetMyPost($id: UUID!) @auth(level: USER) {
post(key: {id: $id},
first: {where: {
id: {eq: $id}
authorUid: {eq_expr: "auth.uid"}}
}}, {
# See the fragment above
...DisplayPost
# also show visibility since it is user-controlled
visibility
}
}
ডেটা ফিল্টার করুন
SQL Connect এর অনুমোদন ব্যবস্থা আপনাকে PUBLIC মতো পূর্বনির্ধারিত অ্যাক্সেস লেভেলের সাথে অত্যাধুনিক ফিল্টার লেখার পাশাপাশি অথ টোকেনের ডেটা ব্যবহার করার সুযোগ দেয়।
অনুমোদন ব্যবস্থাটি আপনাকে কোনো ভিত্তিগত অ্যাক্সেস স্তর ছাড়াই শুধুমাত্র এক্সপ্রেশন ব্যবহার করার সুযোগ দেয়, যেমনটি নিম্নলিখিত কিছু উদাহরণে দেখানো হয়েছে।
রিসোর্স অ্যাট্রিবিউট অনুসারে ফিল্টার করুন
এখানে, অনুমোদন অথ টোকেনের উপর ভিত্তি করে নয়, কারণ ভিত্তি নিরাপত্তা স্তরটি PUBLIC হিসেবে সেট করা আছে। কিন্তু, আমরা আমাদের ডাটাবেসের রেকর্ডগুলোকে সুস্পষ্টভাবে পাবলিক অ্যাক্সেসের জন্য উপযুক্ত হিসেবে সেট করতে পারি; ধরা যাক, আমাদের ডাটাবেসে এমন Post রেকর্ড আছে যেগুলোর visibility 'পাবলিক' হিসেবে সেট করা আছে।
# List all posts marked as 'public' visibility
query ListPublicPosts @auth(level: PUBLIC) {
posts(where: {
# Test that visibility is "public"
visibility: {eq: "public"}
# Only display articles that are already published
publishedAt: {lt_expr: "request.time"}
}) {
# see the fragment above
...DisplayPost
}
}
ব্যবহারকারীর দাবি অনুসারে ফিল্টার করুন
এখানে, ধরে নিন আপনি কাস্টম ইউজার ক্লেইম সেট আপ করেছেন যা আপনার অ্যাপের 'প্রো' প্ল্যানের ব্যবহারকারীদের শনাক্ত করতে অথ টোকেন পাস করে, এবং এই অথ টোকেনটি auth.token.plan ফিল্ড দ্বারা চিহ্নিত থাকে। আপনার এক্সপ্রেশনগুলো এই ফিল্ডের সাথে মিলিয়ে পরীক্ষা করতে পারে।
# List all public or pro posts, only permitted if user has "pro" plan claim
query ProListPosts @auth(expr: "auth.token.plan == 'pro'") {
posts(where: {
# display both public posts and "pro" posts
visibility: {in: ['public', 'pro']},
# only display articles that are already published
publishedAt: {lt_expr: "request.time"},
}) {
# see the fragment above
...DisplayPost
# show visibility so pro users can see which posts are pro\
visibility
}
}
অর্ডার + সীমা দ্বারা ফিল্টার করুন
অথবা, আপনি Post রেকর্ডগুলিতে visibility এমনভাবে সেট করে থাকতে পারেন যাতে বোঝা যায় যে সেগুলি "প্রো" ব্যবহারকারীদের জন্য উপলব্ধ কন্টেন্ট, কিন্তু ডেটার একটি প্রিভিউ বা টিজার তালিকার জন্য, প্রদর্শিত রেকর্ডের সংখ্যা আরও সীমিত করে দিতে পারেন।
# Show 2 oldest Pro post as a preview
query ProTeaser @auth(level: USER) {
posts(
where: {
# show only pro posts
visibility: {eq: "pro"}
# that have already been published more than 30 days ago
publishedAt: {lt_time: {now: true, sub: {days: 30}}}
},
# order by publish time
orderBy: [{publishedAt: DESC}],
# only return two posts
limit: 2
) {
# See the fragment above
...DisplayPost
}
}
ভূমিকা অনুসারে ফিল্টার করুন
আপনার কাস্টম ক্লেইম যদি কোনো admin রোল নির্ধারণ করে, তাহলে আপনি সেই অনুযায়ী অপারেশনগুলো পরীক্ষা ও অনুমোদন করতে পারেন।
# List all posts unconditionally iff the current user has an admin claim
query AdminListPosts @auth(expr: "auth.token.admin == true") {
posts { ...DisplayPost }
}
অনুমোদন ডেটা অনুসন্ধান করতে @check এবং @redact নির্দেশিকাগুলো যোগ করুন।
অনুমোদন ব্যবহারের একটি সাধারণ ক্ষেত্রে, আপনার ডাটাবেসে কাস্টম অনুমোদন রোল সংরক্ষণ করা হয়, যেমন একটি বিশেষ পারমিশন টেবিলে, এবং সেই রোলগুলো ব্যবহার করে ডেটা তৈরি, আপডেট বা মুছে ফেলার জন্য মিউটেশনগুলোকে অনুমোদন দেওয়া হয়।
অথরাইজেশন ডেটা লুকআপ ব্যবহার করে, আপনি একটি ইউজারআইডি-র উপর ভিত্তি করে রোলের জন্য কোয়েরি করতে পারেন এবং মিউটেশনটি অনুমোদিত কিনা তা নির্ধারণ করতে CEL এক্সপ্রেশন ব্যবহার করতে পারেন। উদাহরণস্বরূপ, আপনি একটি UpdateMovieTitle মিউটেশন লিখতে চাইতে পারেন যা একজন অনুমোদিত ক্লায়েন্টকে সিনেমার শিরোনাম আপডেট করার সুযোগ দেয়।
এই আলোচনার বাকি অংশের জন্য, ধরে নিন যে মুভি রিভিউ অ্যাপের ডাটাবেস একটি MoviePermission টেবিলে অনুমোদন ভূমিকা সংরক্ষণ করে।
# MoviePermission
# Suppose a user has an authorization role with respect to records in the Movie table
type MoviePermission @table(key: ["movie", "user"]) {
movie: Movie! # implies another field: movieId: UUID!
user: User!
role: String!
}
মিউটেশনে ব্যবহার
নিম্নলিখিত উদাহরণ বাস্তবায়নে, UpdateMovieTitle মিউটেশনটিতে MoviePermission থেকে ডেটা পুনরুদ্ধার করার জন্য একটি query ফিল্ড এবং অপারেশনটির নিরাপত্তা ও দৃঢ়তা নিশ্চিত করার জন্য নিম্নলিখিত নির্দেশাবলী অন্তর্ভুক্ত রয়েছে:
- সমস্ত অনুমোদন সংক্রান্ত জিজ্ঞাসা ও যাচাইকরণ যেন অ্যাটমিকভাবে সম্পন্ন বা ব্যর্থ হয়, তা নিশ্চিত করার জন্য একটি
@transactionডিরেক্টিভ। -
@redactনির্দেশিকাটি রেসপন্স থেকে কোয়েরির ফলাফল বাদ দেয়, যার অর্থ হলো আমাদের অথরাইজেশন চেক SQL Connect সার্ভারে সম্পন্ন হয় কিন্তু সংবেদনশীল ডেটা ক্লায়েন্টের কাছে প্রকাশ করা হয় না। কোয়েরির ফলাফলের উপর অনুমোদন যুক্তি যাচাই করার জন্য একজোড়া
@checkনির্দেশিকা, যেমন কোনো প্রদত্ত userID-এর পরিবর্তন করার জন্য উপযুক্ত ভূমিকা আছে কিনা তা পরীক্ষা করা।
mutation UpdateMovieTitle($movieId: UUID!, $newTitle: String!) @auth(level: USER) @transaction {
# Step 1: Query and check
query @redact {
moviePermission( # Look up a join table called MoviePermission with a compound key.
key: {movieId: $movieId, userId_expr: "auth.uid"}
# Step 1a: Use @check to test if the user has any role associated with the movie
# Here the `this` binding refers the lookup result, i.e. a MoviePermission object or null
# The `this != null` expression could be omitted since rejecting on null is default behavior
) @check(expr: "this != null", message: "You do not have access to this movie") {
# Step 1b: Check if the user has the editor role for the movie
# Next we execute another @check; now `this` refers to the contents of the `role` field
role @check(expr: "this == 'editor'", message: "You must be an editor of this movie to update title")
}
}
# Step 2: Act
movie_update(id: $movieId, data: {
title: $newTitle
})
}
কোয়েরিতে ব্যবহার করুন
ভূমিকা বা অন্যান্য বিধিনিষেধের উপর ভিত্তি করে কোয়েরি সীমিত করার জন্যও অনুমোদন ডেটা অনুসন্ধান কার্যকর।
নিম্নলিখিত উদাহরণে, যেখানে MoviePermission স্কিমা ব্যবহার করা হয়েছে, কোয়েরিটি যাচাই করে দেখে যে কোনো অনুরোধকারীর একটি মুভি সম্পাদনা করতে পারে এমন ব্যবহারকারীদের দেখার জন্য উপযুক্ত "অ্যাডমিন" ভূমিকা আছে কি না।
query GetMovieEditors($movieId: UUID!) @auth(level: PUBLIC) {
moviePermission(key: { movieId: $movieId, userId_expr: "auth.uid" }) @redact {
role @check(expr: "this == 'admin'", message: "You must be an admin to view all editors of a movie.")
}
moviePermissions(where: { movieId: { eq: $movieId }, role: { eq: "editor" } }) {
user {
id
username
}
}
}
অনুমোদনে পরিহারযোগ্য অ্যান্টিপ্যাটার্ন
পূর্ববর্তী বিভাগে @auth ডিরেক্টিভ ব্যবহার করার সময় অনুসরণীয় ধরণগুলো আলোচনা করা হয়েছে।
কোন কোন গুরুত্বপূর্ণ অ্যান্টিপ্যাটার্ন এড়িয়ে চলতে হবে, সে বিষয়েও আপনার সচেতন থাকা উচিত।
কোয়েরি এবং মিউটেশন আর্গুমেন্টে ইউজার অ্যাট্রিবিউট আইডি এবং অথ টোকেন প্যারামিটার পাস করা থেকে বিরত থাকুন।
Firebase Authentication হলো অথেনটিকেশন ফ্লো উপস্থাপন এবং নিবন্ধিত ব্যবহারকারীর আইডি ও অথ টোকেনে সংরক্ষিত বিভিন্ন ফিল্ডের মতো অথেনটিকেশন ডেটা নিরাপদে সংগ্রহ করার জন্য একটি শক্তিশালী টুল।
কোয়েরি এবং মিউটেশন আর্গুমেন্টে ইউজার আইডি এবং অথ টোকেন ডেটা পাস করা একটি অনুচিত পদ্ধতি।
# Antipattern!
# This incorrectly allows any user to view any other user's posts
query AllMyPosts($userId: String!) @auth(level: USER) {
posts(where: {authorUid: {eq: $userId}}) {
id, text, createdAt
}
}
কোনো ফিল্টার ছাড়া USER অ্যাক্সেস লেভেল ব্যবহার করা থেকে বিরত থাকুন।
গাইডে যেমন একাধিকবার আলোচনা করা হয়েছে, USER , USER_ANON , USER_EMAIL_VERIFIED এর মতো মূল অ্যাক্সেস লেভেলগুলো হলো অনুমোদন যাচাইয়ের জন্য ভিত্তি এবং প্রাথমিক ধাপ, যা ফিল্টার ও এক্সপ্রেশনের মাধ্যমে উন্নত করা যায়। কোন ব্যবহারকারী অনুরোধটি করছে তা যাচাই করার জন্য কোনো সংশ্লিষ্ট ফিল্টার বা এক্সপ্রেশন ছাড়া এই লেভেলগুলো ব্যবহার করা মূলত PUBLIC লেভেল ব্যবহার করার সমতুল্য।
# Antipattern!
# This incorrectly allows any user to view all documents
query ListDocuments @auth(level: USER) {
documents {
id
title
text
}
}
প্রোটোটাইপিংয়ের জন্য PUBLIC বা USER অ্যাক্সেস লেভেল ব্যবহার করা থেকে বিরত থাকুন।
উন্নয়নের গতি বাড়াতে, সমস্ত অপারেশনকে অনুমোদন দেওয়ার এবং আপনার কোড দ্রুত পরীক্ষা করার জন্য কোনো অতিরিক্ত উন্নয়ন ছাড়াই সব অপারেশনকে PUBLIC বা USER অ্যাক্সেস লেভেলে সেট করে দেওয়াটা লোভনীয় মনে হতে পারে।
এইভাবে একেবারে প্রাথমিক প্রোটোটাইপিং সম্পন্ন করার পর, NO_ACCESS থেকে PUBLIC এবং USER লেভেলের মাধ্যমে প্রোডাকশন-রেডি অথরাইজেশনে পরিবর্তন করা শুরু করুন। তবে, এই গাইডে দেখানো অতিরিক্ত লজিক যোগ না করে সেগুলোকে PUBLIC বা USER হিসেবে ডেপ্লয় করবেন না।
# Antipattern!
# This incorrectly allows anyone to delete any post
mutation DeletePost($id: UUID!) @auth(level: PUBLIC) {
post: post_delete(
id: $id,
)
}
যাচাইবিহীন ইমেল ঠিকানার উপর ভিত্তি করে অনুমোদন দেওয়া থেকে বিরত থাকুন।
একটি নির্দিষ্ট ডোমেইনের ব্যবহারকারীদের অ্যাক্সেস দেওয়া অ্যাক্সেস সীমিত করার একটি চমৎকার উপায়। তবে, সাইন-ইন করার সময় যে কেউ একটি ইমেলের মালিকানা দাবি করতে পারে। নিশ্চিত করুন যে আপনি শুধুমাত্র সেইসব ইমেল অ্যাড্রেসকেই অ্যাক্সেস দিচ্ছেন যেগুলো Firebase Authentication-এর মাধ্যমে যাচাই করা হয়েছে।
# Antipattern!
# Anyone can claim an email address during sign-in
mutation CreatePost($text: String!, $visibility: String) @auth(expr: "auth.token.email.endsWith('@example.com')") {
post_insert(data: {
# set the author's uid to the current user uid
authorUid_expr: "auth.uid"
text: $text
visibility: $visibility
})
}
এছাড়াও auth.token.email_verified যাচাই করুন।
mutation CreatePost($text: String!, $visibility: String) @auth(expr: "auth.token.email_verified && auth.token.email.endsWith('@example.com')") {
post_insert(data: {
# set the author's uid to the current user uid
authorUid_expr: "auth.uid"
text: $text
visibility: $visibility
})
}
Firebase CLI দিয়ে অনুমোদন নিরীক্ষা করুন
পূর্বেই যেমন উল্লেখ করা হয়েছে, PUBLIC এবং USER মতো পূর্বনির্ধারিত অ্যাক্সেস লেভেলগুলো শক্তিশালী অথরাইজেশনের সূচনা বিন্দু, এবং এগুলো অতিরিক্ত ফিল্টার ও এক্সপ্রেশন-ভিত্তিক অথরাইজেশন চেকের সাথে ব্যবহার করা উচিত। ব্যবহারের ক্ষেত্রটি (use case) সতর্কতার সাথে বিবেচনা না করে এগুলো এককভাবে ব্যবহার করা উচিত নয়।
আপনি যখন Firebase CLI থেকে firebase deploy ব্যবহার করে সার্ভারে ডিপ্লয় করেন, তখন SQL Connect আপনার কানেক্টর কোড বিশ্লেষণ করে আপনার অথরাইজেশন স্ট্র্যাটেজি নিরীক্ষা করতে সাহায্য করে। এই নিরীক্ষাটি আপনি আপনার কোডবেস পর্যালোচনা করতে ব্যবহার করতে পারেন।
যখন আপনি আপনার কানেক্টরগুলো স্থাপন করবেন, তখন CLI আপনার কানেক্টরের মধ্যে থাকা বিদ্যমান, পরিবর্তিত এবং নতুন অপারেশন কোডের মূল্যায়নগুলো আউটপুট হিসেবে দেখাবে।
পরিবর্তিত এবং নতুন অপারেশনের ক্ষেত্রে, আপনি যখন আপনার নতুন অপারেশনে নির্দিষ্ট অ্যাক্সেস লেভেল ব্যবহার করেন, অথবা যখন বিদ্যমান অপারেশনগুলিকে সেই অ্যাক্সেস লেভেলগুলি ব্যবহার করার জন্য পরিবর্তন করেন, তখন CLI সতর্কবার্তা দেয় এবং আপনার কাছে নিশ্চিতকরণের জন্য অনুরোধ করে।
নিম্নলিখিত ক্ষেত্রে সর্বদা সতর্কতা এবং নির্দেশিকা প্রদর্শিত হয়:
-
PUBLIC
এবং, যখন আপনি auth.uid ব্যবহার করে ফিল্টারের মাধ্যমে নিম্নলিখিত অ্যাক্সেস লেভেলগুলিকে বর্ধিত করেন না, তখন সতর্কবার্তা এবং প্রম্পট প্রদর্শিত হয়:
-
USER -
USER_ANON -
USER_EMAIL_VERIFIED
@auth(insecureReason:) আর্গুমেন্ট ব্যবহার করে অনিরাপদ অপারেশনের সতর্কতাগুলো দমন করুন।
অনেক ক্ষেত্রে, আপনি এই সিদ্ধান্তে উপনীত হবেন যে PUBLIC এবং USER* অ্যাক্সেস লেভেল ব্যবহার করা সম্পূর্ণভাবে যথাযথ।
যখন আপনার কানেক্টরে অনেকগুলো অপারেশন থাকে, তখন আপনি আরও স্পষ্ট ও প্রাসঙ্গিক সিকিউরিটি অডিট আউটপুট চাইতে পারেন, যা এমন অপারেশনগুলোকে বাদ দেবে যেগুলো সাধারণত সতর্কবার্তা দেখায়, কিন্তু আপনি জানেন যে সেগুলোর জন্য সঠিক অ্যাক্সেস লেভেল রয়েছে।
আপনি @auth(insecureReason:) ব্যবহার করে এই ধরনের অপারেশনের জন্য সতর্কবার্তা দমন করতে পারেন। উদাহরণস্বরূপ:
query listItem @auth(level: PUBLIC, insecureReason: "This operation is safe to expose to the public.")
{
items {
id name
}
}
অ্যাপ অ্যাটেস্টেশনের জন্য Firebase App Check ব্যবহার করুন
প্রমাণীকরণ এবং অনুমোদন হলো SQL Connect নিরাপত্তার অত্যন্ত গুরুত্বপূর্ণ উপাদান। প্রমাণীকরণ ও অনুমোদন এবং অ্যাপ অ্যাটেস্টেশন একত্রিত হয়ে একটি অত্যন্ত শক্তিশালী নিরাপত্তা সমাধান তৈরি করে।
Firebase App Check মাধ্যমে অ্যাটেস্টেশন করা থাকলে, আপনার অ্যাপ চালিত ডিভাইসগুলো একটি অ্যাপ বা ডিভাইস অ্যাটেস্টেশন প্রোভাইডার ব্যবহার করবে, যা প্রত্যয়ন করে যে SQL Connect অপারেশনগুলো আপনার আসল অ্যাপ থেকে এবং অনুরোধগুলো একটি আসল ও অক্ষত ডিভাইস থেকে করা হয়েছে। আপনার অ্যাপ থেকে SQL Connect এ করা প্রতিটি অনুরোধের সাথে এই অ্যাটেস্টেশনটি সংযুক্ত থাকে।
কীভাবে SQL Connect এর জন্য App Check সক্রিয় করতে হয় এবং আপনার অ্যাপে এর ক্লায়েন্ট SDK অন্তর্ভুক্ত করতে হয়, তা জানতে App Check ওভারভিউটি দেখুন ।
@auth(level) নির্দেশিকার জন্য প্রমাণীকরণ স্তর
নিম্নলিখিত সারণীতে সমস্ত স্ট্যান্ডার্ড অ্যাক্সেস লেভেল এবং তাদের CEL সমতুল্যগুলি তালিকাভুক্ত করা হয়েছে। প্রমাণীকরণ স্তরগুলি ব্যাপক থেকে সংকীর্ণ ক্রমে তালিকাভুক্ত করা হয়েছে — প্রতিটি স্তর সেই সমস্ত ব্যবহারকারীদের অন্তর্ভুক্ত করে যারা নিম্নলিখিত স্তরগুলির সাথে মেলে।
| স্তর | সংজ্ঞা |
|---|---|
PUBLIC | এই অপারেশনটি প্রমাণীকরণ সহ বা প্রমাণীকরণ ছাড়াই যে কেউ সম্পাদন করতে পারে। বিবেচ্য বিষয়: যেকোনো ব্যবহারকারী ডেটা পড়তে বা পরিবর্তন করতে পারেন। ফায়ারবেস পণ্য বা মিডিয়া তালিকার মতো সর্বজনীনভাবে ব্রাউজযোগ্য ডেটার জন্য এই স্তরের অনুমোদনের সুপারিশ করে। সর্বোত্তম অনুশীলনের উদাহরণ এবং বিকল্পগুলি দেখুন। @auth(expr: "true") এর সমতুল্যএই অ্যাক্সেস লেভেলের সাথে @auth ফিল্টার এবং এক্সপ্রেশন একসাথে ব্যবহার করা যাবে না। এই ধরনের যেকোনো এক্সপ্রেশন 400 ব্যাড রিকোয়েস্ট এরর দিয়ে ব্যর্থ হবে। |
USER_ANON | Firebase Authentication ব্যবহার করে বেনামে লগ ইন করা ব্যবহারকারীসহ যেকোনো শনাক্তকৃত ব্যবহারকারী কোয়েরি বা মিউটেশনটি সম্পাদন করার জন্য অনুমোদিত। দ্রষ্টব্য: USER_ANON হলো USER এর একটি সুপারসেট।বিবেচ্য বিষয়: মনে রাখবেন, এই স্তরের অনুমোদনের জন্য আপনাকে অবশ্যই আপনার কোয়েরি এবং মিউটেশনগুলি সতর্কতার সাথে ডিজাইন করতে হবে। এই স্তরটি ব্যবহারকারীকে Authentication মাধ্যমে বেনামে লগ ইন করার অনুমতি দেয় (স্বয়ংক্রিয় সাইন-ইন যা শুধুমাত্র ব্যবহারকারীর ডিভাইসের সাথে সংযুক্ত), এবং এটি নিজে থেকে ডেটা ব্যবহারকারীর কিনা, এমন কোনো অন্যান্য যাচাই করে না। সর্বোত্তম অনুশীলনের উদাহরণ এবং বিকল্পগুলি দেখুন। যেহেতু Authentication বেনামী লগইন প্রবাহ একটি uid প্রদান করে, তাই USER_ANON স্তরটি এর সমতুল্য@auth(expr: "auth.uid != nil") |
USER | বেনামী সাইন-ইন ব্যবহারকারী ব্যতীত, Firebase Authentication দিয়ে লগ ইন করা যেকোনো ব্যবহারকারী কোয়েরি বা মিউটেশন সম্পাদন করার জন্য অনুমোদিত। বিবেচ্য বিষয়: মনে রাখবেন, এই স্তরের অনুমোদনের জন্য আপনাকে অবশ্যই আপনার কোয়েরি এবং মিউটেশনগুলি সতর্কতার সাথে ডিজাইন করতে হবে। এই স্তরটি শুধুমাত্র পরীক্ষা করে যে ব্যবহারকারী Authentication মাধ্যমে লগ ইন করেছেন কিনা, এবং নিজে থেকে অন্য কোনো পরীক্ষা করে না, যেমন, ডেটা ব্যবহারকারীর কিনা। সর্বোত্তম অনুশীলনের উদাহরণ এবং বিকল্পগুলি দেখুন। @auth(expr: "auth.uid != nil && auth.token.firebase.sign_in_provider != 'anonymous'")" এর সমতুল্য |
USER_EMAIL_VERIFIED | যে কোনো ব্যবহারকারী যিনি একটি যাচাইকৃত ইমেল ঠিকানা দিয়ে Firebase Authentication ব্যবহার করে লগ ইন করেছেন, তিনি কোয়েরি বা মিউটেশনটি সম্পাদন করার জন্য অনুমোদিত। বিবেচ্য বিষয়: যেহেতু ইমেল যাচাইকরণ Authentication ব্যবহার করে করা হয়, এটি একটি আরও শক্তিশালী Authentication পদ্ধতির উপর ভিত্তি করে তৈরি, তাই এই স্তরটি USER বা USER_ANON এর তুলনায় অতিরিক্ত নিরাপত্তা প্রদান করে। এই স্তরটি শুধুমাত্র যাচাই করে যে ব্যবহারকারী একটি যাচাইকৃত ইমেল দিয়ে Authentication মাধ্যমে লগ ইন করেছেন কিনা, এবং এটি নিজে থেকে অন্য কোনো যাচাই করে না, যেমন, ডেটা ব্যবহারকারীর কিনা। সর্বোত্তম অনুশীলনের উদাহরণ এবং বিকল্পগুলি দেখুন।@auth(expr: "auth.uid != nil && auth.token.email_verified")" এর সমতুল্য |
NO_ACCESS | এই অপারেশনটি অ্যাডমিন SDK কনটেক্সটের বাইরে চালানো যাবে না।@auth(expr: "false") এর সমতুল্য |
@auth(expr) এর জন্য CEL রেফারেন্স
এই গাইডের অন্যত্র উদাহরণে যেমন দেখানো হয়েছে, আপনি @auth(expr:) এবং @check নির্দেশাবলী ব্যবহার করে SQL Connect অনুমোদন নিয়ন্ত্রণের জন্য Common Expression Language (CEL)-এ সংজ্ঞায়িত এক্সপ্রেশন ব্যবহার করতে পারেন এবং আপনার তা করা উচিত।
এই বিভাগে এই নির্দেশিকাগুলির জন্য এক্সপ্রেশন তৈরি করার সাথে সম্পর্কিত CEL সিনট্যাক্স আলোচনা করা হয়েছে।
CEL সংক্রান্ত পূর্ণাঙ্গ তথ্য CEL স্পেসিফিকেশনে প্রদান করা হয়েছে।
কোয়েরি এবং মিউটেশনে পাস করা টেস্ট ভেরিয়েবল
@auth(expr) সিনট্যাক্স আপনাকে কোয়েরি এবং মিউটেশন থেকে ভেরিয়েবল অ্যাক্সেস ও পরীক্ষা করার সুযোগ দেয়।
উদাহরণস্বরূপ, আপনি vars.status ব্যবহার করে $status মতো একটি অপারেশন ভেরিয়েবল অন্তর্ভুক্ত করতে পারেন।
mutation Update($id: UUID!, $status: Any) @auth(expr: "has(vars.status)")
এক্সপ্রেশনের জন্য উপলব্ধ ডেটা: অনুরোধ, প্রতিক্রিয়া, এই
আপনি ডেটা ব্যবহার করেন:
-
@auth(expr:)এবং@check(expr:)নির্দেশাবলীতে CEL এক্সপ্রেশন ব্যবহার করে মূল্যায়ন - সার্ভার এক্সপ্রেশন ব্যবহার করে অ্যাসাইনমেন্ট,
<field>_expr.
@auth(expr:) , @check(expr:) , @refresh(onMutationExecuted:) CEL এক্সপ্রেশনগুলো নিম্নলিখিত বিষয়গুলো মূল্যায়ন করতে পারে:
-
request.operationName -
vars(request.variablesএর বিকল্প নাম) -
auth(request.authএর বিকল্প নাম)
মিউটেশন-এর ক্ষেত্রে, আপনি নিম্নলিখিতগুলির বিষয়বস্তু অ্যাক্সেস এবং নির্ধারণ করতে পারেন:
-
response(বহু-ধাপ যুক্তিতে আংশিক ফলাফল যাচাই করার জন্য)
এছাড়াও, @check(expr:) এক্সপ্রেশনগুলো মূল্যায়ন করতে পারে:
-
this(বর্তমান ফিল্ডের মান) -
response(বহু-ধাপ যুক্তিতে আংশিক ফলাফল যাচাই করার জন্য)
এবং @refresh(onMutationExecuted:) এক্সপ্রেশনগুলোর নিম্নলিখিত বাইন্ডিং রয়েছে:
-
mutation.variables -
mutation.auth
request.operationName বাইন্ডিং
request.operarationName বাইন্ডিংটি অপারেশনের ধরণ, অর্থাৎ কোয়েরি অথবা মিউটেশন, সংরক্ষণ করে।
vars বাইন্ডিং (request.vars)
vars বাইন্ডিং আপনার এক্সপ্রেশনকে কোয়েরি বা মিউটেশনে পাস করা সমস্ত ভেরিয়েবল অ্যাক্সেস করার সুযোগ দেয়।
আপনি কোনো এক্সপ্রেশনে সম্পূর্ণ request.variables.<variablename> vars.<variablename> <variablename> ব্যবহার করতে পারেন।
# The following are equivalent
mutation StringType($v: String!) @auth(expr: "vars.v == 'hello'")
mutation StringType($v: String!) @auth(expr: "request.variables.v == 'hello'")
auth বাইন্ডিং (request.auth)
Authentication আপনার ডেটাতে অ্যাক্সেসের অনুরোধকারী ব্যবহারকারীদের শনাক্ত করে এবং সেই তথ্যকে একটি বাইন্ডিং হিসেবে প্রদান করে, যার উপর ভিত্তি করে আপনি আপনার এক্সপ্রেশন তৈরি করতে পারেন।
আপনার ফিল্টার এবং এক্সপ্রেশনে, আপনি request.auth এর উপনাম (alias) হিসেবে auth ব্যবহার করতে পারেন।
অথোরাইজেশন বাইন্ডিং-এ নিম্নলিখিত তথ্য রয়েছে:
-
uid: অনুরোধকারী ব্যবহারকারীকে বরাদ্দ করা একটি অনন্য ব্যবহারকারী আইডি। -
token: Authentication দ্বারা সংগৃহীত মানগুলির একটি ম্যাপ।
auth.token এর বিষয়বস্তু সম্পর্কে আরও বিস্তারিত জানতে auth tokens-এর ডেটা দেখুন।
response বাইন্ডিং
কোনো কোয়েরি বা মিউটেশনের প্রতিক্রিয়ায় সার্ভার কর্তৃক সংগৃহীত ডেটা , ডেটা সংগ্রহের মুহূর্তেই response বাইন্ডিং-এ ধারণ করা থাকে।
অপারেশনটি অগ্রসর হওয়ার সাথে সাথে, প্রতিটি ধাপ সফলভাবে সম্পন্ন হলে, response সফলভাবে সম্পন্ন হওয়া ধাপগুলোর প্রতিক্রিয়া ডেটা অন্তর্ভুক্ত থাকে।
response বাইন্ডিংটি এর সংশ্লিষ্ট অপারেশনের গঠন অনুসারে তৈরি করা হয়, যার মধ্যে (একাধিক) নেস্টেড ফিল্ড এবং (প্রযোজ্য ক্ষেত্রে) এমবেডেড কোয়েরি অন্তর্ভুক্ত থাকে।
মনে রাখবেন যে, যখন আপনি এমবেডেড কোয়েরি রেসপন্স ডেটা অ্যাক্সেস করেন, তখন এমবেডেড কোয়েরিতে অনুরোধ করা ডেটার উপর নির্ভর করে ফিল্ডগুলিতে যেকোনো ডেটা টাইপ থাকতে পারে; যখন আপনি _insert এবং _delete এর মতো মিউটেশন ফিল্ড দ্বারা ফেরত আসা ডেটা অ্যাক্সেস করেন, তখন সেগুলিতে UUID কী, ডিলিটের সংখ্যা, নাল (null) থাকতে পারে ( মিউটেশন রেফারেন্স দেখুন)।
উদাহরণস্বরূপ:
- যে মিউটেশনে একটি এমবেডেড কোয়েরি থাকে, তার
responseবাইন্ডিং-এresponse.query.<fieldName>.<fieldName>....-এ লুকআপ ডেটা থাকে, এক্ষেত্রে,response.query.todoListএবংresponse.query.todoList.priority।
mutation CheckTodoPriority(
$uniqueListName: String!
) {
# This query is identified as `response.query`
query @check(expr: "response.query.todoList.priority == 'high'", message: "This list is not for high priority items!") {
# This field is identified as `response.query.todoList`
todoList(where: { name: $uniqueListName }) {
# This field is identified as `response.query.todoList.priority`
priority
}
}
}
- একটি বহু-ধাপের মিউটেশনে, উদাহরণস্বরূপ একাধিক
_insertফিল্ড থাকলে,responseবাইন্ডিং-এresponse.<fieldName>.<fieldName>....অংশে আংশিক ডেটা থাকে, এই ক্ষেত্রে,response.todoList_insert.id।
mutation CreateTodoListWithFirstItem(
$listName: String!,
$itemContent: String!
) @transaction {
# Step 1
todoList_insert(data: {
id_expr: "uuidV4()",
name: $listName,
})
# Step 2:
todo_insert(data: {
listId_expr: "response.todoList_insert.id" # <-- Grab the newly generated ID from the partial response so far.
content: $itemContent,
})
}
this বাঁধন
this বাইন্ডিংটি সেই ফিল্ডকে মূল্যায়ন করে, যার সাথে @check ডিরেক্টিভটি সংযুক্ত রয়েছে। একটি সাধারণ ক্ষেত্রে, আপনি একক-মানের কোয়েরির ফলাফল মূল্যায়ন করতে পারেন।
mutation UpdateMovieTitle (
$movieId: UUID!,
$newTitle: String!)
@auth(level: USER)
@transaction {
# Step 1: Query and check
query @redact {
moviePermission( # Look up a join table called MoviePermission with a compound key.
key: {movieId: $movieId, userId_expr: "auth.uid"}
) {
# Check if the user has the editor role for the movie. `this` is the string value of `role`.
# If the parent moviePermission is null, the @check will also fail automatically.
role @check(expr: "this == 'editor'", message: "You must be an editor of this movie to update title")
}
}
# Step 2: Act
movie_update(id: $movieId, data: {
title: $newTitle
})
}
যদি কোনো পূর্বপুরুষ একটি তালিকা হওয়ার কারণে ফেরত আসা ফিল্ডটি একাধিকবার আসে, তাহলে প্রতিটি মানের সাথে this বন্ধনী ব্যবহার করে প্রতিটি উপস্থিতি পরীক্ষা করা হয়।
যেকোনো প্রদত্ত পাথের ক্ষেত্রে, যদি কোনো অ্যানসেস্টর null বা [] হয়, তাহলে ফিল্ডটি অ্যাক্সেস করা যাবে না এবং সেই পাথের জন্য CEL ইভ্যালুয়েশন বাদ দেওয়া হবে। অন্য কথায়, ইভ্যালুয়েশন শুধুমাত্র তখনই সম্পন্ন হয় যখন this null বা non- null হয়, কিন্তু কখনোই undefined না।
যখন ফিল্ডটি নিজেই একটি লিস্ট বা অবজেক্ট হয়, this একই কাঠামো অনুসরণ করে (অবজেক্টের ক্ষেত্রে নির্বাচিত সমস্ত ডিসেন্ডেন্ট সহ), যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে।
mutation UpdateMovieTitle2($movieId: UUID!, $newTitle: String!) @auth(level: USER) @transaction {
# Step 1: Query and check
query {
moviePermissions( # Now we query for a list of all matching MoviePermissions.
where: {movieId: {eq: $movieId}, userId: {eq_expr: "auth.uid"}}
# This time we execute the @check on the list, so `this` is the list of objects.
# We can use the `.exists` macro to check if there is at least one matching entry.
) @check(expr: "this.exists(p, p.role == 'editor')", message: "You must be an editor of this movie to update title") {
role
}
}
# Step 2: Act
movie_update(id: $movieId, data: {
title: $newTitle
})
}
জটিল অভিব্যক্তি সিনট্যাক্স
&& এবং || অপারেটরগুলোর সমন্বয়ের মাধ্যমে আপনি আরও জটিল রাশিমালা লিখতে পারেন।
mutation UpsertUser($username: String!) @auth(expr: "(auth != null) && (vars.username == 'joe')")
নিম্নলিখিত বিভাগে সমস্ত উপলব্ধ অপারেটরগুলির বর্ণনা দেওয়া হয়েছে।
অপারেটর এবং অপারেটরের অগ্রাধিকার
অপারেটর এবং তাদের অগ্রাধিকারের ক্রম জানার জন্য নিচের সারণিটি নির্দেশিকা হিসেবে ব্যবহার করুন।
দুটি যথেচ্ছ রাশি a ও b , একটি ক্ষেত্র f , এবং একটি সূচক i দেওয়া আছে।
| অপারেটর | বর্ণনা | সহযোগীতা |
|---|---|---|
a[i] a() af | সূচক, কল, ফিল্ড অ্যাক্সেস | বাম থেকে ডানে |
!a -a | একক নেতিবাচকতা | ডান থেকে বামে |
a/ba%ba*b | গুণক অপারেটর | বাম থেকে ডানে |
a+b ab | যোগাত্মক অপারেটর | বাম থেকে ডানে |
a>b a>=b a<b a<=b | সম্পর্কীয় অপারেটর | বাম থেকে ডানে |
a in b | তালিকা বা মানচিত্রে অস্তিত্ব | বাম থেকে ডানে |
type(a) == t | প্রকার তুলনা, যেখানে t হতে পারে bool, int, float, number, string, list, map, timestamp, বা duration | বাম থেকে ডানে |
a==ba!=b | তুলনা অপারেটর | বাম থেকে ডানে |
a && b | শর্তসাপেক্ষ এবং | বাম থেকে ডানে |
a || b | শর্তসাপেক্ষ অথবা | বাম থেকে ডানে |
a ? true_value : false_value | ত্রয়ী অভিব্যক্তি | বাম থেকে ডানে |
প্রমাণীকরণ টোকেনের ডেটা
auth.token অবজেক্টটিতে নিম্নলিখিত মানগুলি থাকতে পারে:
| মাঠ | বর্ণনা |
|---|---|
email | অ্যাকাউন্টের সাথে যুক্ত ইমেল ঠিকানা, যদি থাকে। |
email_verified | যদি ব্যবহারকারী যাচাই করে থাকেন যে email ঠিকানাটিতে তার প্রবেশাধিকার আছে, তবে true । কিছু পরিষেবা প্রদানকারী তাদের মালিকানাধীন ইমেল ঠিকানাগুলো স্বয়ংক্রিয়ভাবে যাচাই করে। |
phone_number | অ্যাকাউন্টের সাথে যুক্ত ফোন নম্বর, যদি থাকে। |
name | ব্যবহারকারীর প্রদর্শিত নাম, যদি সেট করা থাকে। |
sub | ব্যবহারকারীর ফায়ারবেস ইউআইডি। এটি একটি প্রোজেক্টের মধ্যে অনন্য। |
firebase.identities | এই ব্যবহারকারীর অ্যাকাউন্টের সাথে যুক্ত সমস্ত পরিচয়ের একটি ডিকশনারি। ডিকশনারিটির কী (key) নিম্নলিখিতগুলির যেকোনো একটি হতে পারে: email , phone , google.com , facebook.com , github.com , twitter.com । ডিকশনারিটির ভ্যালু (value) হলো অ্যাকাউন্টের সাথে যুক্ত প্রতিটি আইডেন্টিটি প্রোভাইডারের জন্য অনন্য শনাক্তকারীর অ্যারে। উদাহরণস্বরূপ, auth.token.firebase.identities["google.com"][0] এ অ্যাকাউন্টের সাথে যুক্ত প্রথম গুগল ইউজার আইডি রয়েছে। |
firebase.sign_in_provider | এই টোকেনটি পেতে ব্যবহৃত সাইন-ইন প্রদানকারী। এটি নিম্নলিখিত স্ট্রিংগুলির মধ্যে একটি হতে পারে: custom , password , phone , anonymous , google.com , facebook.com , github.com , twitter.com । |
firebase.tenant | অ্যাকাউন্টের সাথে যুক্ত tenantId, যদি থাকে। উদাহরণস্বরূপ, tenant2-m6tyz |
JWT আইডি টোকেনগুলিতে অতিরিক্ত ক্ষেত্র
আপনি নিম্নলিখিত auth.token ফিল্ডগুলিও অ্যাক্সেস করতে পারেন:
| কাস্টম টোকেন দাবি | ||
|---|---|---|
alg | অ্যালগরিদম | "RS256" |
iss | ইস্যুকারী | আপনার প্রকল্পের পরিষেবা অ্যাকাউন্টের ইমেল ঠিকানা |
sub | বিষয় | আপনার প্রকল্পের পরিষেবা অ্যাকাউন্টের ইমেল ঠিকানা |
aud | দর্শক | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat | ইস্যু-সময় | ইউনিক্স ইপক থেকে বর্তমান সময়, সেকেন্ডে। |
exp | মেয়াদ শেষ হওয়ার সময় | ইউনিক্স ইপক থেকে সেকেন্ডে সেই সময়, যে সময়ে টোকেনটির মেয়াদ শেষ হয়। এটি iat এর চেয়ে সর্বোচ্চ ৩৬০০ সেকেন্ড পরে হতে পারে।দ্রষ্টব্য: এটি শুধুমাত্র কাস্টম টোকেনটির মেয়াদ শেষ হওয়ার সময় নিয়ন্ত্রণ করে। কিন্তু একবার আপনি signInWithCustomToken() ব্যবহার করে কোনো ব্যবহারকারীকে সাইন ইন করালে, তাদের সেশন বাতিল না হওয়া পর্যন্ত বা ব্যবহারকারী সাইন আউট না করা পর্যন্ত তারা ডিভাইসে সাইন ইন করা অবস্থায় থাকবে। |
<claims> (ঐচ্ছিক) | টোকেনে অন্তর্ভুক্ত করার জন্য ঐচ্ছিক কাস্টম ক্লেইম রয়েছে, যা এক্সপ্রেশনে auth.token (বা request.auth.token )-এর মাধ্যমে অ্যাক্সেস করা যায়। উদাহরণস্বরূপ, যদি আপনি adminClaim নামে একটি কাস্টম ক্লেইম তৈরি করেন, তবে আপনি auth.token.adminClaim দিয়ে এটি অ্যাক্সেস করতে পারবেন। | |
এরপর কী?
- Firebase SQL Connect একটি অ্যাডমিন SDK প্রদান করে, যা আপনাকে বিশেষাধিকারপ্রাপ্ত পরিবেশ থেকে কোয়েরি এবং মিউটেশন সম্পাদন করতে দেয়।
- সার্ভিস ও ডেটাবেস ব্যবস্থাপনার নির্দেশিকা থেকে IAM নিরাপত্তা সম্পর্কে জানুন।
Firebase SQL Connect নিম্নলিখিত উপায়ে শক্তিশালী ক্লায়েন্ট-সাইড নিরাপত্তা প্রদান করে:
- মোবাইল এবং ওয়েব ক্লায়েন্ট অনুমোদন
- স্বতন্ত্র কোয়েরি- এবং মিউটেশন-স্তরের অনুমোদন নিয়ন্ত্রণ
- Firebase App Check মাধ্যমে অ্যাপের সত্যায়ন।
SQL Connect নিম্নলিখিত উপায়ে এই নিরাপত্তা আরও প্রসারিত করে:
- সার্ভার-সাইড অনুমোদন
- IAM-এর মাধ্যমে Firebase প্রজেক্ট এবং Cloud SQL ব্যবহারকারীর নিরাপত্তা।
ক্লায়েন্টের কোয়েরি এবং পরিবর্তন অনুমোদন করুন
SQL Connect Firebase Authentication সাথে সম্পূর্ণরূপে সমন্বিত, তাই আপনার ডেটা অ্যাক্সেসকারী ব্যবহারকারীদের (অথরাইজেশন) অ্যাক্সেসের অনুমতি দেওয়ার ডিজাইনে আপনি তাদের সম্পর্কিত বিস্তারিত ডেটা (অথেন্টিকেশন) ব্যবহার করতে পারেন।
SQL Connect কোয়েরি এবং মিউটেশনের জন্য একটি @auth ডিরেক্টিভ প্রদান করে, যা আপনাকে অপারেশনটি অনুমোদন করার জন্য প্রয়োজনীয় অথেনটিকেশনের স্তর নির্ধারণ করতে দেয়। এই নির্দেশিকাটি উদাহরণসহ @auth ডিরেক্টিভটির সাথে পরিচয় করিয়ে দেয় ।
এছাড়াও, SQL Connect মিউটেশনের মধ্যে এমবেড করা কোয়েরি চালানো সমর্থন করে, তাই আপনি আপনার ডাটাবেসে সংরক্ষিত অতিরিক্ত অনুমোদনের মানদণ্ড পুনরুদ্ধার করতে পারেন এবং সেই মানদণ্ডগুলো @check নির্দেশিকায় ব্যবহার করে সিদ্ধান্ত নিতে পারেন যে এনক্লোজিং মিউটেশনগুলো অনুমোদিত কিনা। এই অনুমোদনের ক্ষেত্রে, @redact নির্দেশিকাটি আপনাকে নিয়ন্ত্রণ করতে দেয় যে কোয়েরির ফলাফল ওয়্যার প্রোটোকলে ক্লায়েন্টদের কাছে ফেরত পাঠানো হবে কিনা এবং জেনারেটেড SDK-গুলোতে এমবেড করা কোয়েরিটি বাদ দেওয়া হবে কিনা। উদাহরণসহ এই নির্দেশিকাগুলোর পরিচিতি খুঁজুন।
@auth নির্দেশিকাটি বুঝুন
আপনি @auth ডিরেক্টিভটিকে কয়েকটি পূর্বনির্ধারিত অ্যাক্সেস লেভেলের যেকোনো একটি অনুসরণ করার জন্য প্যারামিটারাইজ করতে পারেন, যা অনেক সাধারণ অ্যাক্সেস পরিস্থিতিকে অন্তর্ভুক্ত করে। এই লেভেলগুলো PUBLIC (যা কোনো প্রকার প্রমাণীকরণ ছাড়াই সকল ক্লায়েন্টকে কোয়েরি এবং মিউটেশন করার অনুমতি দেয়) থেকে NO_ACCESS (যা Firebase Admin SDK ব্যবহার করে বিশেষাধিকারপ্রাপ্ত সার্ভার পরিবেশের বাইরে কোয়েরি এবং মিউটেশন করার অনুমতি দেয় না) পর্যন্ত বিস্তৃত। এই প্রতিটি লেভেল Firebase Authentication দ্বারা প্রদত্ত প্রমাণীকরণ প্রবাহের সাথে সম্পর্কিত।
| স্তর | সংজ্ঞা |
|---|---|
PUBLIC | এই অপারেশনটি প্রমাণীকরণ সহ বা প্রমাণীকরণ ছাড়াই যে কেউ সম্পাদন করতে পারে। |
USER_ANON | Firebase Authentication ব্যবহার করে বেনামে লগ ইন করা ব্যবহারকারীসহ যেকোনো শনাক্তকৃত ব্যবহারকারী কোয়েরি বা মিউটেশনটি সম্পাদন করার জন্য অনুমোদিত। |
USER | বেনামী সাইন-ইন ব্যবহারকারী ব্যতীত, Firebase Authentication দিয়ে লগ ইন করা যেকোনো ব্যবহারকারী কোয়েরি বা মিউটেশন সম্পাদন করার জন্য অনুমোদিত। |
USER_EMAIL_VERIFIED | যে কোনো ব্যবহারকারী যিনি একটি যাচাইকৃত ইমেল ঠিকানা দিয়ে Firebase Authentication ব্যবহার করে লগ ইন করেছেন, তিনি কোয়েরি বা মিউটেশনটি সম্পাদন করার জন্য অনুমোদিত। |
NO_ACCESS | এই অপারেশনটি অ্যাডমিন SDK কনটেক্সটের বাইরে চালানো যাবে না। |
এই পূর্বনির্ধারিত অ্যাক্সেস লেভেলগুলোকে ভিত্তি করে, আপনি @auth ডিরেক্টিভে where ফিল্টার এবং সার্ভারে ইভ্যালুয়েট করা কমন এক্সপ্রেশন ল্যাঙ্গুয়েজ (CEL) এক্সপ্রেশন ব্যবহার করে জটিল ও শক্তিশালী অথরাইজেশন চেক সংজ্ঞায়িত করতে পারেন।
সাধারণ অনুমোদন পরিস্থিতিগুলো বাস্তবায়ন করতে @auth নির্দেশিকাটি ব্যবহার করুন।
পূর্বনির্ধারিত প্রবেশাধিকার স্তরগুলো অনুমোদনের প্রাথমিক ধাপ ।
USER অ্যাক্সেস লেভেল হলো শুরু করার জন্য সবচেয়ে বহুল ব্যবহৃত প্রাথমিক স্তর।
সম্পূর্ণ সুরক্ষিত অ্যাক্সেস USER লেভেলের উপর ভিত্তি করে তৈরি হবে, যার সাথে থাকবে ফিল্টার এবং এক্সপ্রেশন যা ব্যবহারকারীর অ্যাট্রিবিউট, রিসোর্স অ্যাট্রিবিউট, রোল এবং অন্যান্য বিষয় যাচাই করবে। USER_ANON এবং USER_EMAIL_VERIFIED লেভেলগুলো হলো USER লেভেলেরই ভিন্ন রূপ।
এক্সপ্রেশন সিনট্যাক্স আপনাকে একটি auth অবজেক্ট ব্যবহার করে ডেটা মূল্যায়ন করতে দেয়, যা অপারেশনগুলির সাথে প্রেরিত প্রমাণীকরণ ডেটা উপস্থাপন করে; এর মধ্যে অথ টোকেনে থাকা স্ট্যান্ডার্ড ডেটা এবং টোকেনে থাকা কাস্টম ডেটা উভয়ই অন্তর্ভুক্ত। auth অবজেক্টে উপলব্ধ ফিল্ডগুলির তালিকার জন্য, রেফারেন্স বিভাগটি দেখুন।
অবশ্যই এমন কিছু ব্যবহারের ক্ষেত্র আছে যেখানে শুরু করার জন্য PUBLIC ই সঠিক অ্যাক্সেস লেভেল। তবে, অ্যাক্সেস লেভেল সবসময়ই একটি সূচনা বিন্দু, এবং শক্তিশালী নিরাপত্তার জন্য অতিরিক্ত ফিল্টার ও এক্সপ্রেশনের প্রয়োজন হয়।
এই নির্দেশিকায় এখন USER এবং PUBLIC উপর ভিত্তি করে কীভাবে নির্মাণ করা যায় তার উদাহরণ দেওয়া হলো।
একটি অনুপ্রেরণামূলক উদাহরণ
নিম্নলিখিত সেরা অনুশীলনের উদাহরণগুলি একটি ব্লগিং প্ল্যাটফর্মের জন্য নিম্নলিখিত স্কিমাটিকে নির্দেশ করে, যেখানে নির্দিষ্ট কিছু কন্টেন্ট একটি পেমেন্ট প্ল্যানের আড়ালে লক করা থাকে।
এই ধরনের একটি প্ল্যাটফর্ম সম্ভবত Users এবং Posts আদলে তৈরি হবে।
type User @table(key: "uid") {
uid: String!
name: String
birthday: Date
createdAt: Timestamp! @default(expr: "request.time")
}
type Post @table {
author: User!
text: String!
# "one of 'draft', 'public', or 'pro'"
visibility: String! @default(value: "draft")
# "the time at which the post should be considered published. defaults to
# immediately"
publishedAt: Timestamp! @default(expr: "request.time")
createdAt: Timestamp! @default(expr: "request.time")
updatedAt: Timestamp! @default(expr: "request.time")
}
ব্যবহারকারীর মালিকানাধীন সম্পদ
ফায়ারবেস পরামর্শ দেয় যে আপনি এমন ফিল্টার এবং এক্সপ্রেশন লিখুন যা কোনো রিসোর্সের উপর ব্যবহারকারীর মালিকানা যাচাই করে, যেমন Posts মালিকানার ক্ষেত্রে।
নিম্নলিখিত উদাহরণগুলিতে, এক্সপ্রেশন ব্যবহার করে অথ টোকেন থেকে ডেটা পড়া এবং তুলনা করা হয়। প্রচলিত রীতি হলো, অথেন্টিকেশন টোকেনে পাঠানো auth.uid (ইউজার আইডি)-এর সাথে সংরক্ষিত authorUid তুলনা করার জন্য where: {authorUid: {eq_expr: "auth.uid"}} মতো এক্সপ্রেশন ব্যবহার করা।
তৈরি করুন
এই অনুমোদন প্রক্রিয়াটি শুরু হয় প্রতিটি নতুন Post অথ টোকেন থেকে auth.uid authorUid ফিল্ড হিসেবে যোগ করার মাধ্যমে, যাতে পরবর্তী অনুমোদন পরীক্ষাগুলোতে তুলনা করা যায়।
# Create a new post as the current user
mutation CreatePost($text: String!, $visibility: String) @auth(level: USER) {
post_insert(data: {
# set the author's uid to the current user uid
authorUid_expr: "auth.uid"
text: $text
visibility: $visibility
})
}
আপডেট
যখন কোনো ক্লায়েন্ট একটি Post আপডেট করার চেষ্টা করে, তখন আপনি প্রদত্ত auth.uid সংরক্ষিত authorUid সাথে মিলিয়ে দেখতে পারেন।
# Update one of the current user's posts
mutation UpdatePost($id: UUID!, $text: String, $visibility: String) @auth(level:USER) {
post_update(
# only update posts whose author is the current user
first: { where: {
id: {eq: $id}
authorUid: {eq_expr: "auth.uid"}
}}
data: {
text: $text
visibility: $visibility
# insert the current server time for updatedAt
updatedAt_expr: "request.time"
}
)
}
মুছে ফেলুন
মুছে ফেলার কার্যক্রম অনুমোদন করতেও একই কৌশল ব্যবহার করা হয়।
# Delete one of the current user's posts
mutation DeletePost($id: UUID!) @auth(level: USER) {
post_delete(
# only delete posts whose author is the current user
first: { where: {
id: {eq: $id}
authorUid: {eq_expr: "auth.uid"}
}}
)
}
# Common display information for a post
fragment DisplayPost on Post {
id, text, createdAt, updatedAt
author { uid, name }
}
তালিকা
# List all posts belonging to the current user
query ListMyPosts @auth(level: USER) {
posts(where: {
userUid: {eq_expr: "auth.uid"}
}) {
# See the fragment above
...DisplayPost
# also show visibility since it is user-controlled
visibility
}
}
পান
# Get a post only if it belongs to the current user
query GetMyPost($id: UUID!) @auth(level: USER) {
post(key: {id: $id},
first: {where: {
id: {eq: $id}
authorUid: {eq_expr: "auth.uid"}}
}}, {
# See the fragment above
...DisplayPost
# also show visibility since it is user-controlled
visibility
}
}
ডেটা ফিল্টার করুন
SQL Connect এর অনুমোদন ব্যবস্থা আপনাকে PUBLIC মতো পূর্বনির্ধারিত অ্যাক্সেস লেভেলের সাথে অত্যাধুনিক ফিল্টার লেখার পাশাপাশি অথ টোকেনের ডেটা ব্যবহার করার সুযোগ দেয়।
অনুমোদন ব্যবস্থাটি আপনাকে কোনো ভিত্তিগত অ্যাক্সেস স্তর ছাড়াই শুধুমাত্র এক্সপ্রেশন ব্যবহার করার সুযোগ দেয়, যেমনটি নিম্নলিখিত কিছু উদাহরণে দেখানো হয়েছে।
রিসোর্স অ্যাট্রিবিউট অনুসারে ফিল্টার করুন
এখানে, অনুমোদন অথ টোকেনের উপর ভিত্তি করে নয়, কারণ ভিত্তি নিরাপত্তা স্তরটি PUBLIC হিসেবে সেট করা আছে। কিন্তু, আমরা আমাদের ডাটাবেসের রেকর্ডগুলোকে সুস্পষ্টভাবে পাবলিক অ্যাক্সেসের জন্য উপযুক্ত হিসেবে সেট করতে পারি; ধরা যাক, আমাদের ডাটাবেসে এমন Post রেকর্ড আছে যেগুলোর visibility 'পাবলিক' হিসেবে সেট করা আছে।
# List all posts marked as 'public' visibility
query ListPublicPosts @auth(level: PUBLIC) {
posts(where: {
# Test that visibility is "public"
visibility: {eq: "public"}
# Only display articles that are already published
publishedAt: {lt_expr: "request.time"}
}) {
# see the fragment above
...DisplayPost
}
}
ব্যবহারকারীর দাবি অনুসারে ফিল্টার করুন
এখানে, ধরে নিন আপনি কাস্টম ইউজার ক্লেইম সেট আপ করেছেন যা আপনার অ্যাপের 'প্রো' প্ল্যানের ব্যবহারকারীদের শনাক্ত করতে অথ টোকেন পাস করে, এবং এই অথ টোকেনটি auth.token.plan ফিল্ড দ্বারা চিহ্নিত থাকে। আপনার এক্সপ্রেশনগুলো এই ফিল্ডের সাথে মিলিয়ে পরীক্ষা করতে পারে।
# List all public or pro posts, only permitted if user has "pro" plan claim
query ProListPosts @auth(expr: "auth.token.plan == 'pro'") {
posts(where: {
# display both public posts and "pro" posts
visibility: {in: ['public', 'pro']},
# only display articles that are already published
publishedAt: {lt_expr: "request.time"},
}) {
# see the fragment above
...DisplayPost
# show visibility so pro users can see which posts are pro\
visibility
}
}
অর্ডার + সীমা দ্বারা ফিল্টার করুন
অথবা, আপনি Post রেকর্ডগুলিতে visibility এমনভাবে সেট করে থাকতে পারেন যাতে বোঝা যায় যে সেগুলি "প্রো" ব্যবহারকারীদের জন্য উপলব্ধ কন্টেন্ট, কিন্তু ডেটার একটি প্রিভিউ বা টিজার তালিকার জন্য, প্রদর্শিত রেকর্ডের সংখ্যা আরও সীমিত করে দিতে পারেন।
# Show 2 oldest Pro post as a preview
query ProTeaser @auth(level: USER) {
posts(
where: {
# show only pro posts
visibility: {eq: "pro"}
# that have already been published more than 30 days ago
publishedAt: {lt_time: {now: true, sub: {days: 30}}}
},
# order by publish time
orderBy: [{publishedAt: DESC}],
# only return two posts
limit: 2
) {
# See the fragment above
...DisplayPost
}
}
ভূমিকা অনুসারে ফিল্টার করুন
আপনার কাস্টম ক্লেইম যদি কোনো admin রোল নির্ধারণ করে, তাহলে আপনি সেই অনুযায়ী অপারেশনগুলো পরীক্ষা ও অনুমোদন করতে পারেন।
# List all posts unconditionally iff the current user has an admin claim
query AdminListPosts @auth(expr: "auth.token.admin == true") {
posts { ...DisplayPost }
}
অনুমোদন ডেটা অনুসন্ধান করতে @check এবং @redact নির্দেশিকাগুলো যোগ করুন।
অনুমোদন ব্যবহারের একটি সাধারণ ক্ষেত্রে, আপনার ডাটাবেসে কাস্টম অনুমোদন রোল সংরক্ষণ করা হয়, যেমন একটি বিশেষ পারমিশন টেবিলে, এবং সেই রোলগুলো ব্যবহার করে ডেটা তৈরি, আপডেট বা মুছে ফেলার জন্য মিউটেশনগুলোকে অনুমোদন দেওয়া হয়।
অথরাইজেশন ডেটা লুকআপ ব্যবহার করে, আপনি একটি ইউজারআইডি-র উপর ভিত্তি করে রোলের জন্য কোয়েরি করতে পারেন এবং মিউটেশনটি অনুমোদিত কিনা তা নির্ধারণ করতে CEL এক্সপ্রেশন ব্যবহার করতে পারেন। উদাহরণস্বরূপ, আপনি একটি UpdateMovieTitle মিউটেশন লিখতে চাইতে পারেন যা একজন অনুমোদিত ক্লায়েন্টকে সিনেমার শিরোনাম আপডেট করার সুযোগ দেয়।
এই আলোচনার বাকি অংশের জন্য, ধরে নিন যে মুভি রিভিউ অ্যাপের ডাটাবেস একটি MoviePermission টেবিলে অনুমোদন ভূমিকা সংরক্ষণ করে।
# MoviePermission
# Suppose a user has an authorization role with respect to records in the Movie table
type MoviePermission @table(key: ["movie", "user"]) {
movie: Movie! # implies another field: movieId: UUID!
user: User!
role: String!
}
মিউটেশনে ব্যবহার
নিম্নলিখিত উদাহরণ বাস্তবায়নে, UpdateMovieTitle মিউটেশনটিতে MoviePermission থেকে ডেটা পুনরুদ্ধার করার জন্য একটি query ফিল্ড এবং অপারেশনটির নিরাপত্তা ও দৃঢ়তা নিশ্চিত করার জন্য নিম্নলিখিত নির্দেশাবলী অন্তর্ভুক্ত রয়েছে:
- সমস্ত অনুমোদন সংক্রান্ত জিজ্ঞাসা ও যাচাইকরণ যেন অ্যাটমিকভাবে সম্পন্ন বা ব্যর্থ হয়, তা নিশ্চিত করার জন্য একটি
@transactionডিরেক্টিভ। -
@redactনির্দেশিকাটি রেসপন্স থেকে কোয়েরির ফলাফল বাদ দেয়, যার অর্থ হলো আমাদের অথরাইজেশন চেক SQL Connect সার্ভারে সম্পন্ন হয় কিন্তু সংবেদনশীল ডেটা ক্লায়েন্টের কাছে প্রকাশ করা হয় না। কোয়েরির ফলাফলের উপর অনুমোদন যুক্তি যাচাই করার জন্য একজোড়া
@checkনির্দেশিকা, যেমন কোনো প্রদত্ত userID-এর পরিবর্তন করার জন্য উপযুক্ত ভূমিকা আছে কিনা তা পরীক্ষা করা।
mutation UpdateMovieTitle($movieId: UUID!, $newTitle: String!) @auth(level: USER) @transaction {
# Step 1: Query and check
query @redact {
moviePermission( # Look up a join table called MoviePermission with a compound key.
key: {movieId: $movieId, userId_expr: "auth.uid"}
# Step 1a: Use @check to test if the user has any role associated with the movie
# Here the `this` binding refers the lookup result, i.e. a MoviePermission object or null
# The `this != null` expression could be omitted since rejecting on null is default behavior
) @check(expr: "this != null", message: "You do not have access to this movie") {
# Step 1b: Check if the user has the editor role for the movie
# Next we execute another @check; now `this` refers to the contents of the `role` field
role @check(expr: "this == 'editor'", message: "You must be an editor of this movie to update title")
}
}
# Step 2: Act
movie_update(id: $movieId, data: {
title: $newTitle
})
}
কোয়েরিতে ব্যবহার করুন
ভূমিকা বা অন্যান্য বিধিনিষেধের উপর ভিত্তি করে কোয়েরি সীমিত করার জন্যও অনুমোদন ডেটা অনুসন্ধান কার্যকর।
নিম্নলিখিত উদাহরণে, যেখানে MoviePermission স্কিমা ব্যবহার করা হয়েছে, কোয়েরিটি যাচাই করে দেখে যে কোনো অনুরোধকারীর একটি মুভি সম্পাদনা করতে পারে এমন ব্যবহারকারীদের দেখার জন্য উপযুক্ত "অ্যাডমিন" ভূমিকা আছে কি না।
query GetMovieEditors($movieId: UUID!) @auth(level: PUBLIC) {
moviePermission(key: { movieId: $movieId, userId_expr: "auth.uid" }) @redact {
role @check(expr: "this == 'admin'", message: "You must be an admin to view all editors of a movie.")
}
moviePermissions(where: { movieId: { eq: $movieId }, role: { eq: "editor" } }) {
user {
id
username
}
}
}
অনুমোদনে পরিহারযোগ্য অ্যান্টিপ্যাটার্ন
পূর্ববর্তী বিভাগে @auth ডিরেক্টিভ ব্যবহার করার সময় অনুসরণীয় ধরণগুলো আলোচনা করা হয়েছে।
কোন কোন গুরুত্বপূর্ণ অ্যান্টিপ্যাটার্ন এড়িয়ে চলতে হবে, সে বিষয়েও আপনার সচেতন থাকা উচিত।
কোয়েরি এবং মিউটেশন আর্গুমেন্টে ইউজার অ্যাট্রিবিউট আইডি এবং অথ টোকেন প্যারামিটার পাস করা থেকে বিরত থাকুন।
Firebase Authentication হলো অথেনটিকেশন ফ্লো উপস্থাপন এবং নিবন্ধিত ব্যবহারকারীর আইডি ও অথ টোকেনে সংরক্ষিত বিভিন্ন ফিল্ডের মতো অথেনটিকেশন ডেটা নিরাপদে সংগ্রহ করার জন্য একটি শক্তিশালী টুল।
কোয়েরি এবং মিউটেশন আর্গুমেন্টে ইউজার আইডি এবং অথ টোকেন ডেটা পাস করা একটি অনুচিত পদ্ধতি।
# Antipattern!
# This incorrectly allows any user to view any other user's posts
query AllMyPosts($userId: String!) @auth(level: USER) {
posts(where: {authorUid: {eq: $userId}}) {
id, text, createdAt
}
}
কোনো ফিল্টার ছাড়া USER অ্যাক্সেস লেভেল ব্যবহার করা থেকে বিরত থাকুন।
গাইডে যেমন একাধিকবার আলোচনা করা হয়েছে, USER , USER_ANON , USER_EMAIL_VERIFIED এর মতো মূল অ্যাক্সেস লেভেলগুলো হলো অনুমোদন যাচাইয়ের জন্য ভিত্তি এবং প্রাথমিক ধাপ, যা ফিল্টার ও এক্সপ্রেশনের মাধ্যমে উন্নত করা যায়। কোন ব্যবহারকারী অনুরোধটি করছে তা যাচাই করার জন্য কোনো সংশ্লিষ্ট ফিল্টার বা এক্সপ্রেশন ছাড়া এই লেভেলগুলো ব্যবহার করা মূলত PUBLIC লেভেল ব্যবহার করার সমতুল্য।
# Antipattern!
# This incorrectly allows any user to view all documents
query ListDocuments @auth(level: USER) {
documents {
id
title
text
}
}
প্রোটোটাইপিংয়ের জন্য PUBLIC বা USER অ্যাক্সেস লেভেল ব্যবহার করা থেকে বিরত থাকুন।
উন্নয়নের গতি বাড়াতে, সমস্ত অপারেশনকে অনুমোদন দেওয়ার এবং আপনার কোড দ্রুত পরীক্ষা করার জন্য কোনো অতিরিক্ত উন্নয়ন ছাড়াই সব অপারেশনকে PUBLIC বা USER অ্যাক্সেস লেভেলে সেট করে দেওয়াটা লোভনীয় মনে হতে পারে।
এইভাবে একেবারে প্রাথমিক প্রোটোটাইপিং সম্পন্ন করার পর, NO_ACCESS থেকে PUBLIC এবং USER লেভেলের মাধ্যমে প্রোডাকশন-রেডি অথরাইজেশনে পরিবর্তন করা শুরু করুন। তবে, এই গাইডে দেখানো অতিরিক্ত লজিক যোগ না করে সেগুলোকে PUBLIC বা USER হিসেবে ডেপ্লয় করবেন না।
# Antipattern!
# This incorrectly allows anyone to delete any post
mutation DeletePost($id: UUID!) @auth(level: PUBLIC) {
post: post_delete(
id: $id,
)
}
যাচাইবিহীন ইমেল ঠিকানার উপর ভিত্তি করে অনুমোদন দেওয়া থেকে বিরত থাকুন।
একটি নির্দিষ্ট ডোমেইনের ব্যবহারকারীদের অ্যাক্সেস দেওয়া অ্যাক্সেস সীমিত করার একটি চমৎকার উপায়। তবে, সাইন-ইন করার সময় যে কেউ একটি ইমেলের মালিকানা দাবি করতে পারে। নিশ্চিত করুন যে আপনি শুধুমাত্র সেইসব ইমেল অ্যাড্রেসকেই অ্যাক্সেস দিচ্ছেন যেগুলো Firebase Authentication-এর মাধ্যমে যাচাই করা হয়েছে।
# Antipattern!
# Anyone can claim an email address during sign-in
mutation CreatePost($text: String!, $visibility: String) @auth(expr: "auth.token.email.endsWith('@example.com')") {
post_insert(data: {
# set the author's uid to the current user uid
authorUid_expr: "auth.uid"
text: $text
visibility: $visibility
})
}
এছাড়াও auth.token.email_verified যাচাই করুন।
mutation CreatePost($text: String!, $visibility: String) @auth(expr: "auth.token.email_verified && auth.token.email.endsWith('@example.com')") {
post_insert(data: {
# set the author's uid to the current user uid
authorUid_expr: "auth.uid"
text: $text
visibility: $visibility
})
}
Firebase CLI দিয়ে অনুমোদন নিরীক্ষা করুন
পূর্বেই যেমন উল্লেখ করা হয়েছে, PUBLIC এবং USER মতো পূর্বনির্ধারিত অ্যাক্সেস লেভেলগুলো শক্তিশালী অথরাইজেশনের সূচনা বিন্দু, এবং এগুলো অতিরিক্ত ফিল্টার ও এক্সপ্রেশন-ভিত্তিক অথরাইজেশন চেকের সাথে ব্যবহার করা উচিত। ব্যবহারের ক্ষেত্রটি (use case) সতর্কতার সাথে বিবেচনা না করে এগুলো এককভাবে ব্যবহার করা উচিত নয়।
আপনি যখন Firebase CLI থেকে firebase deploy ব্যবহার করে সার্ভারে ডিপ্লয় করেন, তখন SQL Connect আপনার কানেক্টর কোড বিশ্লেষণ করে আপনার অথরাইজেশন স্ট্র্যাটেজি নিরীক্ষা করতে সাহায্য করে। এই নিরীক্ষাটি আপনি আপনার কোডবেস পর্যালোচনা করতে ব্যবহার করতে পারেন।
যখন আপনি আপনার কানেক্টরগুলো স্থাপন করবেন, তখন CLI আপনার কানেক্টরের মধ্যে থাকা বিদ্যমান, পরিবর্তিত এবং নতুন অপারেশন কোডের মূল্যায়নগুলো আউটপুট হিসেবে দেখাবে।
পরিবর্তিত এবং নতুন অপারেশনের ক্ষেত্রে, আপনি যখন আপনার নতুন অপারেশনে নির্দিষ্ট অ্যাক্সেস লেভেল ব্যবহার করেন, অথবা যখন বিদ্যমান অপারেশনগুলিকে সেই অ্যাক্সেস লেভেলগুলি ব্যবহার করার জন্য পরিবর্তন করেন, তখন CLI সতর্কবার্তা দেয় এবং আপনার কাছে নিশ্চিতকরণের জন্য অনুরোধ করে।
নিম্নলিখিত ক্ষেত্রে সর্বদা সতর্কতা এবং নির্দেশিকা প্রদর্শিত হয়:
-
PUBLIC
এবং, যখন আপনি auth.uid ব্যবহার করে ফিল্টারের মাধ্যমে নিম্নলিখিত অ্যাক্সেস লেভেলগুলিকে বর্ধিত করেন না, তখন সতর্কবার্তা এবং প্রম্পট প্রদর্শিত হয়:
-
USER -
USER_ANON -
USER_EMAIL_VERIFIED
@auth(insecureReason:) আর্গুমেন্ট ব্যবহার করে অনিরাপদ অপারেশনের সতর্কতাগুলো দমন করুন।
অনেক ক্ষেত্রে, আপনি এই সিদ্ধান্তে উপনীত হবেন যে PUBLIC এবং USER* অ্যাক্সেস লেভেল ব্যবহার করা সম্পূর্ণভাবে যথাযথ।
যখন আপনার কানেক্টরে অনেকগুলো অপারেশন থাকে, তখন আপনি আরও স্পষ্ট ও প্রাসঙ্গিক সিকিউরিটি অডিট আউটপুট চাইতে পারেন, যা এমন অপারেশনগুলোকে বাদ দেবে যেগুলো সাধারণত সতর্কবার্তা দেখায়, কিন্তু আপনি জানেন যে সেগুলোর জন্য সঠিক অ্যাক্সেস লেভেল রয়েছে।
আপনি @auth(insecureReason:) ব্যবহার করে এই ধরনের অপারেশনের জন্য সতর্কবার্তা দমন করতে পারেন। উদাহরণস্বরূপ:
query listItem @auth(level: PUBLIC, insecureReason: "This operation is safe to expose to the public.")
{
items {
id name
}
}
অ্যাপ অ্যাটেস্টেশনের জন্য Firebase App Check ব্যবহার করুন
প্রমাণীকরণ এবং অনুমোদন হলো SQL Connect নিরাপত্তার অত্যন্ত গুরুত্বপূর্ণ উপাদান। প্রমাণীকরণ ও অনুমোদন এবং অ্যাপ অ্যাটেস্টেশন একত্রিত হয়ে একটি অত্যন্ত শক্তিশালী নিরাপত্তা সমাধান তৈরি করে।
Firebase App Check মাধ্যমে অ্যাটেস্টেশন করা থাকলে, আপনার অ্যাপ চালিত ডিভাইসগুলো একটি অ্যাপ বা ডিভাইস অ্যাটেস্টেশন প্রোভাইডার ব্যবহার করবে, যা প্রত্যয়ন করে যে SQL Connect অপারেশনগুলো আপনার আসল অ্যাপ থেকে এবং অনুরোধগুলো একটি আসল ও অক্ষত ডিভাইস থেকে করা হয়েছে। আপনার অ্যাপ থেকে SQL Connect এ করা প্রতিটি অনুরোধের সাথে এই অ্যাটেস্টেশনটি সংযুক্ত থাকে।
কীভাবে SQL Connect এর জন্য App Check সক্রিয় করতে হয় এবং আপনার অ্যাপে এর ক্লায়েন্ট SDK অন্তর্ভুক্ত করতে হয়, তা জানতে App Check ওভারভিউটি দেখুন ।
@auth(level) নির্দেশিকার জন্য প্রমাণীকরণ স্তর
নিম্নলিখিত সারণীতে সমস্ত স্ট্যান্ডার্ড অ্যাক্সেস লেভেল এবং তাদের CEL সমতুল্যগুলি তালিকাভুক্ত করা হয়েছে। প্রমাণীকরণ স্তরগুলি ব্যাপক থেকে সংকীর্ণ ক্রমে তালিকাভুক্ত করা হয়েছে — প্রতিটি স্তর সেই সমস্ত ব্যবহারকারীদের অন্তর্ভুক্ত করে যারা নিম্নলিখিত স্তরগুলির সাথে মেলে।
| স্তর | সংজ্ঞা |
|---|---|
PUBLIC | এই অপারেশনটি প্রমাণীকরণ সহ বা প্রমাণীকরণ ছাড়াই যে কেউ সম্পাদন করতে পারে। বিবেচ্য বিষয়: যেকোনো ব্যবহারকারী ডেটা পড়তে বা পরিবর্তন করতে পারেন। ফায়ারবেস পণ্য বা মিডিয়া তালিকার মতো সর্বজনীনভাবে ব্রাউজযোগ্য ডেটার জন্য এই স্তরের অনুমোদনের সুপারিশ করে। সর্বোত্তম অনুশীলনের উদাহরণ এবং বিকল্পগুলি দেখুন। @auth(expr: "true") এর সমতুল্যএই অ্যাক্সেস লেভেলের সাথে @auth ফিল্টার এবং এক্সপ্রেশন একসাথে ব্যবহার করা যাবে না। এই ধরনের যেকোনো এক্সপ্রেশন 400 ব্যাড রিকোয়েস্ট এরর দিয়ে ব্যর্থ হবে। |
USER_ANON | Any identified user, including those who have logged in anonymously with Firebase Authentication , is authorized to perform the query or mutation. Note: USER_ANON is a superset of USER .Considerations: Note that you must carefully design your queries and mutations for this level of authorization. This level allows user to be logged in anonymously (automatic sign-in tied only to a user device) with Authentication , and does not on its own perform other checks on, for example, whether data belongs to the user. See the best practice examples and alternatives . Since Authentication anonymous login flows issue a uid , the USER_ANON level is equivalent to@auth(expr: "auth.uid != nil") |
USER | Any user who has logged in with Firebase Authentication is authorized to perform the query or mutation except anonymous sign-in users. Considerations: Note that you must carefully design your queries and mutations for this level of authorization. This level only checks that the user is logged in with Authentication , and does not on its own perform other checks on, for example, whether data belongs to the user. See the best practice examples and alternatives . Equivalent to @auth(expr: "auth.uid != nil && auth.token.firebase.sign_in_provider != 'anonymous'")" |
USER_EMAIL_VERIFIED | Any user who has logged in with Firebase Authentication with a verified email address is authorized to perform the query or mutation. Considerations: Since email verification is performed using Authentication , it's based on a more robust Authentication method, thus this level provides additional security compared to USER or USER_ANON . This level only checks that the user is logged in with Authentication with a verified email, and does not on its own perform other checks on, for example, whether data belongs to the user. See the best practice examples and alternatives .Equivalent to @auth(expr: "auth.uid != nil && auth.token.email_verified")" |
NO_ACCESS | This operation cannot be executed outside an Admin SDK context. Equivalent to @auth(expr: "false") |
CEL Reference for @auth(expr)
As shown in examples elsewhere in this guide, you can and should use expressions defined in Common Expression Language (CEL) to control authorization for SQL Connect using @auth(expr:) and @check directives.
This section covers CEL syntax relevant to creating expressions for these directives.
CEL সংক্রান্ত পূর্ণাঙ্গ তথ্য CEL স্পেসিফিকেশনে প্রদান করা হয়েছে।
কোয়েরি এবং মিউটেশনে পাস করা টেস্ট ভেরিয়েবল
@auth(expr) সিনট্যাক্স আপনাকে কোয়েরি এবং মিউটেশন থেকে ভেরিয়েবল অ্যাক্সেস ও পরীক্ষা করার সুযোগ দেয়।
উদাহরণস্বরূপ, আপনি vars.status ব্যবহার করে $status মতো একটি অপারেশন ভেরিয়েবল অন্তর্ভুক্ত করতে পারেন।
mutation Update($id: UUID!, $status: Any) @auth(expr: "has(vars.status)")
এক্সপ্রেশনের জন্য উপলব্ধ ডেটা: অনুরোধ, প্রতিক্রিয়া, এই
আপনি ডেটা ব্যবহার করেন:
-
@auth(expr:)এবং@check(expr:)নির্দেশাবলীতে CEL এক্সপ্রেশন ব্যবহার করে মূল্যায়ন - সার্ভার এক্সপ্রেশন ব্যবহার করে অ্যাসাইনমেন্ট,
<field>_expr.
@auth(expr:) , @check(expr:) , @refresh(onMutationExecuted:) CEL এক্সপ্রেশনগুলো নিম্নলিখিত বিষয়গুলো মূল্যায়ন করতে পারে:
-
request.operationName -
vars(request.variablesএর বিকল্প নাম) -
auth(request.authএর বিকল্প নাম)
মিউটেশন-এর ক্ষেত্রে, আপনি নিম্নলিখিতগুলির বিষয়বস্তু অ্যাক্সেস এবং নির্ধারণ করতে পারেন:
-
response(বহু-ধাপ যুক্তিতে আংশিক ফলাফল যাচাই করার জন্য)
এছাড়াও, @check(expr:) এক্সপ্রেশনগুলো মূল্যায়ন করতে পারে:
-
this(বর্তমান ফিল্ডের মান) -
response(বহু-ধাপ যুক্তিতে আংশিক ফলাফল যাচাই করার জন্য)
এবং @refresh(onMutationExecuted:) এক্সপ্রেশনগুলোর নিম্নলিখিত বাইন্ডিং রয়েছে:
-
mutation.variables -
mutation.auth
request.operationName বাইন্ডিং
request.operarationName বাইন্ডিংটি অপারেশনের ধরণ, অর্থাৎ কোয়েরি অথবা মিউটেশন, সংরক্ষণ করে।
vars বাইন্ডিং (request.vars)
vars বাইন্ডিং আপনার এক্সপ্রেশনকে কোয়েরি বা মিউটেশনে পাস করা সমস্ত ভেরিয়েবল অ্যাক্সেস করার সুযোগ দেয়।
আপনি কোনো এক্সপ্রেশনে সম্পূর্ণ request.variables.<variablename> vars.<variablename> <variablename> ব্যবহার করতে পারেন।
# The following are equivalent
mutation StringType($v: String!) @auth(expr: "vars.v == 'hello'")
mutation StringType($v: String!) @auth(expr: "request.variables.v == 'hello'")
auth বাইন্ডিং (request.auth)
Authentication আপনার ডেটাতে অ্যাক্সেসের অনুরোধকারী ব্যবহারকারীদের শনাক্ত করে এবং সেই তথ্যকে একটি বাইন্ডিং হিসেবে প্রদান করে, যার উপর ভিত্তি করে আপনি আপনার এক্সপ্রেশন তৈরি করতে পারেন।
আপনার ফিল্টার এবং এক্সপ্রেশনে, আপনি request.auth এর উপনাম (alias) হিসেবে auth ব্যবহার করতে পারেন।
অথোরাইজেশন বাইন্ডিং-এ নিম্নলিখিত তথ্য রয়েছে:
-
uid: অনুরোধকারী ব্যবহারকারীকে বরাদ্দ করা একটি অনন্য ব্যবহারকারী আইডি। -
token: Authentication দ্বারা সংগৃহীত মানগুলির একটি ম্যাপ।
auth.token এর বিষয়বস্তু সম্পর্কে আরও বিস্তারিত জানতে auth tokens-এর ডেটা দেখুন।
response বাইন্ডিং
কোনো কোয়েরি বা মিউটেশনের প্রতিক্রিয়ায় সার্ভার কর্তৃক সংগৃহীত ডেটা , ডেটা সংগ্রহের মুহূর্তেই response বাইন্ডিং-এ ধারণ করা থাকে।
অপারেশনটি অগ্রসর হওয়ার সাথে সাথে, প্রতিটি ধাপ সফলভাবে সম্পন্ন হলে, response সফলভাবে সম্পন্ন হওয়া ধাপগুলোর প্রতিক্রিয়া ডেটা অন্তর্ভুক্ত থাকে।
response বাইন্ডিংটি এর সংশ্লিষ্ট অপারেশনের গঠন অনুসারে তৈরি করা হয়, যার মধ্যে (একাধিক) নেস্টেড ফিল্ড এবং (প্রযোজ্য ক্ষেত্রে) এমবেডেড কোয়েরি অন্তর্ভুক্ত থাকে।
মনে রাখবেন যে, যখন আপনি এমবেডেড কোয়েরি রেসপন্স ডেটা অ্যাক্সেস করেন, তখন এমবেডেড কোয়েরিতে অনুরোধ করা ডেটার উপর নির্ভর করে ফিল্ডগুলিতে যেকোনো ডেটা টাইপ থাকতে পারে; যখন আপনি _insert এবং _delete এর মতো মিউটেশন ফিল্ড দ্বারা ফেরত আসা ডেটা অ্যাক্সেস করেন, তখন সেগুলিতে UUID কী, ডিলিটের সংখ্যা, নাল (null) থাকতে পারে ( মিউটেশন রেফারেন্স দেখুন)।
উদাহরণস্বরূপ:
- যে মিউটেশনে একটি এমবেডেড কোয়েরি থাকে, তার
responseবাইন্ডিং-এresponse.query.<fieldName>.<fieldName>....-এ লুকআপ ডেটা থাকে, এক্ষেত্রে,response.query.todoListএবংresponse.query.todoList.priority।
mutation CheckTodoPriority(
$uniqueListName: String!
) {
# This query is identified as `response.query`
query @check(expr: "response.query.todoList.priority == 'high'", message: "This list is not for high priority items!") {
# This field is identified as `response.query.todoList`
todoList(where: { name: $uniqueListName }) {
# This field is identified as `response.query.todoList.priority`
priority
}
}
}
- একটি বহু-ধাপের মিউটেশনে, উদাহরণস্বরূপ একাধিক
_insertফিল্ড থাকলে,responseবাইন্ডিং-এresponse.<fieldName>.<fieldName>....অংশে আংশিক ডেটা থাকে, এই ক্ষেত্রে,response.todoList_insert.id।
mutation CreateTodoListWithFirstItem(
$listName: String!,
$itemContent: String!
) @transaction {
# Step 1
todoList_insert(data: {
id_expr: "uuidV4()",
name: $listName,
})
# Step 2:
todo_insert(data: {
listId_expr: "response.todoList_insert.id" # <-- Grab the newly generated ID from the partial response so far.
content: $itemContent,
})
}
this বাঁধন
this বাইন্ডিংটি সেই ফিল্ডকে মূল্যায়ন করে, যার সাথে @check ডিরেক্টিভটি সংযুক্ত রয়েছে। একটি সাধারণ ক্ষেত্রে, আপনি একক-মানের কোয়েরির ফলাফল মূল্যায়ন করতে পারেন।
mutation UpdateMovieTitle (
$movieId: UUID!,
$newTitle: String!)
@auth(level: USER)
@transaction {
# Step 1: Query and check
query @redact {
moviePermission( # Look up a join table called MoviePermission with a compound key.
key: {movieId: $movieId, userId_expr: "auth.uid"}
) {
# Check if the user has the editor role for the movie. `this` is the string value of `role`.
# If the parent moviePermission is null, the @check will also fail automatically.
role @check(expr: "this == 'editor'", message: "You must be an editor of this movie to update title")
}
}
# Step 2: Act
movie_update(id: $movieId, data: {
title: $newTitle
})
}
যদি কোনো পূর্বপুরুষ একটি তালিকা হওয়ার কারণে ফেরত আসা ফিল্ডটি একাধিকবার আসে, তাহলে প্রতিটি মানের সাথে this বন্ধনী ব্যবহার করে প্রতিটি উপস্থিতি পরীক্ষা করা হয়।
যেকোনো প্রদত্ত পাথের ক্ষেত্রে, যদি কোনো অ্যানসেস্টর null বা [] হয়, তাহলে ফিল্ডটি অ্যাক্সেস করা যাবে না এবং সেই পাথের জন্য CEL ইভ্যালুয়েশন বাদ দেওয়া হবে। অন্য কথায়, ইভ্যালুয়েশন শুধুমাত্র তখনই সম্পন্ন হয় যখন this null বা non- null হয়, কিন্তু কখনোই undefined না।
যখন ফিল্ডটি নিজেই একটি লিস্ট বা অবজেক্ট হয়, this একই কাঠামো অনুসরণ করে (অবজেক্টের ক্ষেত্রে নির্বাচিত সমস্ত ডিসেন্ডেন্ট সহ), যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে।
mutation UpdateMovieTitle2($movieId: UUID!, $newTitle: String!) @auth(level: USER) @transaction {
# Step 1: Query and check
query {
moviePermissions( # Now we query for a list of all matching MoviePermissions.
where: {movieId: {eq: $movieId}, userId: {eq_expr: "auth.uid"}}
# This time we execute the @check on the list, so `this` is the list of objects.
# We can use the `.exists` macro to check if there is at least one matching entry.
) @check(expr: "this.exists(p, p.role == 'editor')", message: "You must be an editor of this movie to update title") {
role
}
}
# Step 2: Act
movie_update(id: $movieId, data: {
title: $newTitle
})
}
জটিল অভিব্যক্তি সিনট্যাক্স
&& এবং || অপারেটরগুলোর সমন্বয়ের মাধ্যমে আপনি আরও জটিল রাশিমালা লিখতে পারেন।
mutation UpsertUser($username: String!) @auth(expr: "(auth != null) && (vars.username == 'joe')")
নিম্নলিখিত বিভাগে সমস্ত উপলব্ধ অপারেটরগুলির বর্ণনা দেওয়া হয়েছে।
অপারেটর এবং অপারেটরের অগ্রাধিকার
অপারেটর এবং তাদের অগ্রাধিকারের ক্রম জানার জন্য নিচের সারণিটি নির্দেশিকা হিসেবে ব্যবহার করুন।
দুটি যথেচ্ছ রাশি a ও b , একটি ক্ষেত্র f , এবং একটি সূচক i দেওয়া আছে।
| অপারেটর | বর্ণনা | সহযোগীতা |
|---|---|---|
a[i] a() af | সূচক, কল, ফিল্ড অ্যাক্সেস | বাম থেকে ডানে |
!a -a | একক নেতিবাচকতা | ডান থেকে বামে |
a/ba%ba*b | গুণক অপারেটর | বাম থেকে ডানে |
a+b ab | যোগাত্মক অপারেটর | বাম থেকে ডানে |
a>b a>=b a<b a<=b | সম্পর্কীয় অপারেটর | বাম থেকে ডানে |
a in b | তালিকা বা মানচিত্রে অস্তিত্ব | বাম থেকে ডানে |
type(a) == t | প্রকার তুলনা, যেখানে t হতে পারে bool, int, float, number, string, list, map, timestamp, বা duration | বাম থেকে ডানে |
a==ba!=b | তুলনা অপারেটর | বাম থেকে ডানে |
a && b | শর্তসাপেক্ষ এবং | বাম থেকে ডানে |
a || b | শর্তসাপেক্ষ অথবা | বাম থেকে ডানে |
a ? true_value : false_value | ত্রয়ী অভিব্যক্তি | বাম থেকে ডানে |
প্রমাণীকরণ টোকেনের ডেটা
auth.token অবজেক্টটিতে নিম্নলিখিত মানগুলি থাকতে পারে:
| মাঠ | বর্ণনা |
|---|---|
email | অ্যাকাউন্টের সাথে যুক্ত ইমেল ঠিকানা, যদি থাকে। |
email_verified | যদি ব্যবহারকারী যাচাই করে থাকেন যে email ঠিকানাটিতে তার প্রবেশাধিকার আছে, তবে true । কিছু পরিষেবা প্রদানকারী তাদের মালিকানাধীন ইমেল ঠিকানাগুলো স্বয়ংক্রিয়ভাবে যাচাই করে। |
phone_number | অ্যাকাউন্টের সাথে যুক্ত ফোন নম্বর, যদি থাকে। |
name | ব্যবহারকারীর প্রদর্শিত নাম, যদি সেট করা থাকে। |
sub | ব্যবহারকারীর ফায়ারবেস ইউআইডি। এটি একটি প্রোজেক্টের মধ্যে অনন্য। |
firebase.identities | এই ব্যবহারকারীর অ্যাকাউন্টের সাথে যুক্ত সমস্ত পরিচয়ের একটি ডিকশনারি। ডিকশনারিটির কী (key) নিম্নলিখিতগুলির যেকোনো একটি হতে পারে: email , phone , google.com , facebook.com , github.com , twitter.com । ডিকশনারিটির ভ্যালু (value) হলো অ্যাকাউন্টের সাথে যুক্ত প্রতিটি আইডেন্টিটি প্রোভাইডারের জন্য অনন্য শনাক্তকারীর অ্যারে। উদাহরণস্বরূপ, auth.token.firebase.identities["google.com"][0] এ অ্যাকাউন্টের সাথে যুক্ত প্রথম গুগল ইউজার আইডি রয়েছে। |
firebase.sign_in_provider | এই টোকেনটি পেতে ব্যবহৃত সাইন-ইন প্রদানকারী। এটি নিম্নলিখিত স্ট্রিংগুলির মধ্যে একটি হতে পারে: custom , password , phone , anonymous , google.com , facebook.com , github.com , twitter.com । |
firebase.tenant | অ্যাকাউন্টের সাথে যুক্ত tenantId, যদি থাকে। উদাহরণস্বরূপ, tenant2-m6tyz |
JWT আইডি টোকেনগুলিতে অতিরিক্ত ক্ষেত্র
আপনি নিম্নলিখিত auth.token ফিল্ডগুলিও অ্যাক্সেস করতে পারেন:
| কাস্টম টোকেন দাবি | ||
|---|---|---|
alg | অ্যালগরিদম | "RS256" |
iss | ইস্যুকারী | আপনার প্রকল্পের পরিষেবা অ্যাকাউন্টের ইমেল ঠিকানা |
sub | বিষয় | আপনার প্রকল্পের পরিষেবা অ্যাকাউন্টের ইমেল ঠিকানা |
aud | দর্শক | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat | ইস্যু-সময় | ইউনিক্স ইপক থেকে বর্তমান সময়, সেকেন্ডে। |
exp | মেয়াদ শেষ হওয়ার সময় | ইউনিক্স ইপক থেকে সেকেন্ডে সেই সময়, যে সময়ে টোকেনটির মেয়াদ শেষ হয়। এটি iat এর চেয়ে সর্বোচ্চ ৩৬০০ সেকেন্ড পরে হতে পারে।দ্রষ্টব্য: এটি শুধুমাত্র কাস্টম টোকেনটির মেয়াদ শেষ হওয়ার সময় নিয়ন্ত্রণ করে। কিন্তু একবার আপনি signInWithCustomToken() ব্যবহার করে কোনো ব্যবহারকারীকে সাইন ইন করালে, তাদের সেশন বাতিল না হওয়া পর্যন্ত বা ব্যবহারকারী সাইন আউট না করা পর্যন্ত তারা ডিভাইসে সাইন ইন করা অবস্থায় থাকবে। |
<claims> (ঐচ্ছিক) | টোকেনে অন্তর্ভুক্ত করার জন্য ঐচ্ছিক কাস্টম ক্লেইম রয়েছে, যা এক্সপ্রেশনে auth.token (বা request.auth.token )-এর মাধ্যমে অ্যাক্সেস করা যায়। উদাহরণস্বরূপ, যদি আপনি adminClaim নামে একটি কাস্টম ক্লেইম তৈরি করেন, তবে আপনি auth.token.adminClaim দিয়ে এটি অ্যাক্সেস করতে পারবেন। | |
এরপর কী?
- Firebase SQL Connect provides an Admin SDK to let you perform queries and mutations from privileged environments .
- Learn about IAM security in the guide for managing services and databases .
Firebase SQL Connect provides robust client-side security with:
- Mobile and web client authorization
- Individual query- and mutation-level authorization controls
- App attestation with Firebase App Check .
SQL Connect extends this security with:
- Server-side authorization
- Firebase project and Cloud SQL user security with IAM.
Authorize client queries and mutations
SQL Connect is fully integrated with Firebase Authentication , so you can use rich data about users who are accessing your data (authentication) in your design for what data those users can access (authorization).
SQL Connect provides an @auth directive for queries and mutations that lets you set the level of authentication required to authorize the operation. This guide introduces the @auth directive, with examples .
In addition, SQL Connect supports execution of queries embedded in mutations, so you can retrieve additional authorization criteria you've stored in your database, and use those criteria in @check directives to decide if enclosing mutations are authorized. For this authorization case, the @redact directive allows you control whether query results are returned to clients in the wire protocol and the embedded query omitted in generated SDKs. Find the introduction to these directives, with examples .
Understand the @auth directive
You can parameterize the @auth directive to follow one of several preset access levels that cover many common access scenarios. These levels range from PUBLIC (which allows queries and mutations from all clients without authentication of any kind) to NO_ACCESS (which disallows queries and mutations outside of privileged server environments using the Firebase Admin SDK ). Each of these levels is correlated with authentication flows provided by Firebase Authentication .
| স্তর | সংজ্ঞা |
|---|---|
PUBLIC | The operation can be executed by anyone with or without authentication. |
USER_ANON | Any identified user, including those who have logged in anonymously with Firebase Authentication , is authorized to perform the query or mutation. |
USER | Any user who has logged in with Firebase Authentication is authorized to perform the query or mutation except anonymous sign-in users. |
USER_EMAIL_VERIFIED | Any user who has logged in with Firebase Authentication with a verified email address is authorized to perform the query or mutation. |
NO_ACCESS | This operation cannot be executed outside an Admin SDK context. |
Using these preset access levels as a starting point, you can define complex and robust authorization checks in the @auth directive using where filters and Common Expression Language (CEL) expressions evaluated on the server.
Use the @auth directive to implement common authorization scenarios
The preset access levels are the starting point for authorization.
The USER access level is the most widely useful basic level to start with.
Fully secure access will build on the USER level plus filters and expressions that check user attributes, resource attributes, roles and other checks. The USER_ANON and USER_EMAIL_VERIFIED levels are variations on the USER case.
Expression syntax lets you evaluate data using an auth object representing authentication data passed with operations, both standard data in auth tokens and custom data in tokens. For the list of fields available in the auth object, see the reference section .
There are of course use cases where PUBLIC is the correct access level to start with. Again, an access level is always a starting point, and additional filters and expressions are needed for robust security.
This guide now gives examples of how to build on USER and PUBLIC .
A motivating example
The following best practice examples refer to the following schema for a blogging platform with certain content locked behind a payment plan.
Such a platform would likely model Users and Posts .
type User @table(key: "uid") {
uid: String!
name: String
birthday: Date
createdAt: Timestamp! @default(expr: "request.time")
}
type Post @table {
author: User!
text: String!
# "one of 'draft', 'public', or 'pro'"
visibility: String! @default(value: "draft")
# "the time at which the post should be considered published. defaults to
# immediately"
publishedAt: Timestamp! @default(expr: "request.time")
createdAt: Timestamp! @default(expr: "request.time")
updatedAt: Timestamp! @default(expr: "request.time")
}
User-owned resources
Firebase recommends that you write filters and expressions that test user ownership of a resource, in the following cases, ownership of Posts .
In the following examples, data from auth tokens is read and compared using expressions. The typical pattern is to use expressions like where: {authorUid: {eq_expr: "auth.uid"}} to compare a stored authorUid to the auth.uid (user ID) passed in the authentication token.
তৈরি করুন
This authorization practice starts by adding the auth.uid from the auth token to each new Post as an authorUid field to allow comparison in subsequence authorization tests.
# Create a new post as the current user
mutation CreatePost($text: String!, $visibility: String) @auth(level: USER) {
post_insert(data: {
# set the author's uid to the current user uid
authorUid_expr: "auth.uid"
text: $text
visibility: $visibility
})
}
আপডেট
When a client attempts to update a Post , you can test the passed auth.uid against the stored authorUid .
# Update one of the current user's posts
mutation UpdatePost($id: UUID!, $text: String, $visibility: String) @auth(level:USER) {
post_update(
# only update posts whose author is the current user
first: { where: {
id: {eq: $id}
authorUid: {eq_expr: "auth.uid"}
}}
data: {
text: $text
visibility: $visibility
# insert the current server time for updatedAt
updatedAt_expr: "request.time"
}
)
}
মুছে ফেলুন
The same technique is used to authorize delete operations.
# Delete one of the current user's posts
mutation DeletePost($id: UUID!) @auth(level: USER) {
post_delete(
# only delete posts whose author is the current user
first: { where: {
id: {eq: $id}
authorUid: {eq_expr: "auth.uid"}
}}
)
}
# Common display information for a post
fragment DisplayPost on Post {
id, text, createdAt, updatedAt
author { uid, name }
}
তালিকা
# List all posts belonging to the current user
query ListMyPosts @auth(level: USER) {
posts(where: {
userUid: {eq_expr: "auth.uid"}
}) {
# See the fragment above
...DisplayPost
# also show visibility since it is user-controlled
visibility
}
}
পান
# Get a post only if it belongs to the current user
query GetMyPost($id: UUID!) @auth(level: USER) {
post(key: {id: $id},
first: {where: {
id: {eq: $id}
authorUid: {eq_expr: "auth.uid"}}
}}, {
# See the fragment above
...DisplayPost
# also show visibility since it is user-controlled
visibility
}
}
Filter Data
SQL Connect 's authorization system lets you write sophisticated filters combined with preset access levels like PUBLIC as well as by using data from auth tokens.
The authorization system also lets you use expressions only, without a base access level, as shown in some of the following examples.
Filter by resource attributes
Here, authorization is not based on auth tokens since the base security level is set to PUBLIC . But, we can explicitly set records in our database as suitable for public access; assume we have Post records in our database with visibility set to "public".
# List all posts marked as 'public' visibility
query ListPublicPosts @auth(level: PUBLIC) {
posts(where: {
# Test that visibility is "public"
visibility: {eq: "public"}
# Only display articles that are already published
publishedAt: {lt_expr: "request.time"}
}) {
# see the fragment above
...DisplayPost
}
}
Filter by user claims
Here, assume you've set up custom user claims that pass in auth tokens to identify users in a "pro" plan for your app, flagged with an auth.token.plan field in the auth token. Your expressions can test against this field.
# List all public or pro posts, only permitted if user has "pro" plan claim
query ProListPosts @auth(expr: "auth.token.plan == 'pro'") {
posts(where: {
# display both public posts and "pro" posts
visibility: {in: ['public', 'pro']},
# only display articles that are already published
publishedAt: {lt_expr: "request.time"},
}) {
# see the fragment above
...DisplayPost
# show visibility so pro users can see which posts are pro\
visibility
}
}
Filter by order + limit
Or again, you may have set visibility in Post records to identify they are content available for "pro" users, but for a preview or teaser listing of data, further limit the number of records returned.
# Show 2 oldest Pro post as a preview
query ProTeaser @auth(level: USER) {
posts(
where: {
# show only pro posts
visibility: {eq: "pro"}
# that have already been published more than 30 days ago
publishedAt: {lt_time: {now: true, sub: {days: 30}}}
},
# order by publish time
orderBy: [{publishedAt: DESC}],
# only return two posts
limit: 2
) {
# See the fragment above
...DisplayPost
}
}
Filter by role
If your custom claim defines an admin role, you can test and authorize operations accordingly.
# List all posts unconditionally iff the current user has an admin claim
query AdminListPosts @auth(expr: "auth.token.admin == true") {
posts { ...DisplayPost }
}
Add the @check and @redact directives to look up authorization data
A common authorization use case involves storing custom authorization roles in your database, for example in a special permissions table, and using those roles to authorize mutations to create, update, or delete data.
Using authorization data lookups, you can query for roles based on a userID and use CEL expressions to decide if the mutation is authorized. For example, you might want to write an UpdateMovieTitle mutation that lets an authorized client update movie titles.
For the rest of this discussion, assume the movie review app database stores an authorization role in a MoviePermission table.
# MoviePermission
# Suppose a user has an authorization role with respect to records in the Movie table
type MoviePermission @table(key: ["movie", "user"]) {
movie: Movie! # implies another field: movieId: UUID!
user: User!
role: String!
}
Use in mutations
In the following example implementation, the UpdateMovieTitle mutation includes a query field to retrieve data from MoviePermission , and the following directives to ensure the operation is secure and robust:
- A
@transactiondirective to ensure all authorization queries and checks are completed or fail atomically. - The
@redactdirective to omit query results from the response, meaning our authorization check is performed on the SQL Connect server but sensitive data is not exposed to the client. A pair of
@checkdirectives to evaluate authorization logic on query results, such as testing that a given userID has an appropriate role to make modifications.
mutation UpdateMovieTitle($movieId: UUID!, $newTitle: String!) @auth(level: USER) @transaction {
# Step 1: Query and check
query @redact {
moviePermission( # Look up a join table called MoviePermission with a compound key.
key: {movieId: $movieId, userId_expr: "auth.uid"}
# Step 1a: Use @check to test if the user has any role associated with the movie
# Here the `this` binding refers the lookup result, i.e. a MoviePermission object or null
# The `this != null` expression could be omitted since rejecting on null is default behavior
) @check(expr: "this != null", message: "You do not have access to this movie") {
# Step 1b: Check if the user has the editor role for the movie
# Next we execute another @check; now `this` refers to the contents of the `role` field
role @check(expr: "this == 'editor'", message: "You must be an editor of this movie to update title")
}
}
# Step 2: Act
movie_update(id: $movieId, data: {
title: $newTitle
})
}
Use in queries
Authorization data lookups are also useful to restrict queries based on roles or other restrictions.
In the following example, which also uses the MoviePermission schema, the query checks whether a requestor has an appropriate "admin" role to view users who can edit a movie.
query GetMovieEditors($movieId: UUID!) @auth(level: PUBLIC) {
moviePermission(key: { movieId: $movieId, userId_expr: "auth.uid" }) @redact {
role @check(expr: "this == 'admin'", message: "You must be an admin to view all editors of a movie.")
}
moviePermissions(where: { movieId: { eq: $movieId }, role: { eq: "editor" } }) {
user {
id
username
}
}
}
Antipatterns to avoid in authorization
The previous section covers patterns to follow when using the @auth directive.
You should also be aware of important antipatterns to avoid.
Avoid passing user attributes IDs and auth token parameters in query and mutation arguments
Firebase Authentication is a powerful tool for presenting authentication flows and securely capturing authentication data such as registered user IDs and numerous fields stored in auth tokens.
It's not a recommended practice to pass user IDs and auth token data in query and mutation arguments.
# Antipattern!
# This incorrectly allows any user to view any other user's posts
query AllMyPosts($userId: String!) @auth(level: USER) {
posts(where: {authorUid: {eq: $userId}}) {
id, text, createdAt
}
}
Avoid using the USER access level without any filters
As discussed several times in the guide, the core access levels like USER , USER_ANON , USER_EMAIL_VERIFIED are baselines and starting points for authorization checks, to be enhanced with filters and expressions. Using these levels without a corresponding filter or expression that checks which user is performing the request is essentially equivalent to using the PUBLIC level.
# Antipattern!
# This incorrectly allows any user to view all documents
query ListDocuments @auth(level: USER) {
documents {
id
title
text
}
}
Avoid using PUBLIC or USER access level for prototyping
To speed up development, it can be tempting to set all operations to the PUBLIC access level or to USER access level without further enhancements to authorize all operations and let you quickly test your code.
When you've done very initial prototyping this way, begin to switch from NO_ACCESS to production-ready authorization with PUBLIC and USER levels. However, don't deploy them as PUBLIC or USER without adding additional logic as shown in this guide.
# Antipattern!
# This incorrectly allows anyone to delete any post
mutation DeletePost($id: UUID!) @auth(level: PUBLIC) {
post: post_delete(
id: $id,
)
}
Avoid basing authorization on unverified email addresses
Granting access to users on a particular domain is a great way to limit access. However, anyone can claim to own an email during sign-in. Ensure you only grant access to email addresses that have been verified through Firebase Authentication.
# Antipattern!
# Anyone can claim an email address during sign-in
mutation CreatePost($text: String!, $visibility: String) @auth(expr: "auth.token.email.endsWith('@example.com')") {
post_insert(data: {
# set the author's uid to the current user uid
authorUid_expr: "auth.uid"
text: $text
visibility: $visibility
})
}
Also check auth.token.email_verified
mutation CreatePost($text: String!, $visibility: String) @auth(expr: "auth.token.email_verified && auth.token.email.endsWith('@example.com')") {
post_insert(data: {
# set the author's uid to the current user uid
authorUid_expr: "auth.uid"
text: $text
visibility: $visibility
})
}
Audit authorization with the Firebase CLI
As indicated earlier, preset access levels such as PUBLIC and USER are the starting point for robust authorization, and should be used with additional filter and expression-based authorization checks. They shouldn't be used on their own without careful consideration of the use case.
SQL Connect helps you audit your authorization strategy by analyzing your connector code when you deploy to the server using firebase deploy from the Firebase CLI. You can use this audit to help you review your codebase.
When you deploy your connectors, the CLI will output assessments for existing, modified and new operation code in your connector.
For modified and new operations, the CLI issues warnings and prompts you for confirmation when you use certain access levels in your new operations, or when you modify existing operations to use those access levels.
Warnings and prompts always occur for:
-
PUBLIC
And, warnings and prompts occur on the following access levels when you don't augment them with filters using auth.uid :
-
USER -
USER_ANON -
USER_EMAIL_VERIFIED
Suppress insecure operation warnings with the @auth(insecureReason:) argument
In many cases, you will conclude that using the PUBLIC and USER* access levels is perfectly appropriate.
When your connector contains many operations, you may want clearer, more relevant security audit output that omits operations that would normally trigger a warning, but you know have the correct access level.
You can suppress warnings for such operations with @auth(insecureReason:) . For example:
query listItem @auth(level: PUBLIC, insecureReason: "This operation is safe to expose to the public.")
{
items {
id name
}
}
Use Firebase App Check for app attestation
Authentication and authorization are critical components of SQL Connect security. Authentication and authorization combined with app attestation makes for a very robust security solution.
With attestation through Firebase App Check , devices running your app will use an app or device attestation provider that attests that SQL Connect operations originate from your authentic app and requests originate from an authentic, untampered device. This attestation is attached to every request your app makes to SQL Connect .
To learn how to enable App Check for SQL Connect and include its client SDK in your app, have a look at the App Check overview .
Authentication levels for the @auth(level) directive
The following table lists all standard access levels and their CEL equivalents. Authentication levels are listed from broad to narrow -- each level encompasses all users who match following levels.
| স্তর | সংজ্ঞা |
|---|---|
PUBLIC | The operation can be executed by anyone with or without authentication. Considerations: Data can be read or modified by any user. Firebase recommends this level of authorization for publicly-browsable data like product or media listings. See the best practice examples and alternatives . Equivalent to @auth(expr: "true")@auth filters and expressions cannot be used in combination with this access level. Any such expressions will fail with a 400 bad request error. |
USER_ANON | Any identified user, including those who have logged in anonymously with Firebase Authentication , is authorized to perform the query or mutation. Note: USER_ANON is a superset of USER .Considerations: Note that you must carefully design your queries and mutations for this level of authorization. This level allows user to be logged in anonymously (automatic sign-in tied only to a user device) with Authentication , and does not on its own perform other checks on, for example, whether data belongs to the user. See the best practice examples and alternatives . Since Authentication anonymous login flows issue a uid , the USER_ANON level is equivalent to@auth(expr: "auth.uid != nil") |
USER | Any user who has logged in with Firebase Authentication is authorized to perform the query or mutation except anonymous sign-in users. Considerations: Note that you must carefully design your queries and mutations for this level of authorization. This level only checks that the user is logged in with Authentication , and does not on its own perform other checks on, for example, whether data belongs to the user. See the best practice examples and alternatives . Equivalent to @auth(expr: "auth.uid != nil && auth.token.firebase.sign_in_provider != 'anonymous'")" |
USER_EMAIL_VERIFIED | Any user who has logged in with Firebase Authentication with a verified email address is authorized to perform the query or mutation. Considerations: Since email verification is performed using Authentication , it's based on a more robust Authentication method, thus this level provides additional security compared to USER or USER_ANON . This level only checks that the user is logged in with Authentication with a verified email, and does not on its own perform other checks on, for example, whether data belongs to the user. See the best practice examples and alternatives .Equivalent to @auth(expr: "auth.uid != nil && auth.token.email_verified")" |
NO_ACCESS | This operation cannot be executed outside an Admin SDK context. Equivalent to @auth(expr: "false") |
CEL Reference for @auth(expr)
As shown in examples elsewhere in this guide, you can and should use expressions defined in Common Expression Language (CEL) to control authorization for SQL Connect using @auth(expr:) and @check directives.
This section covers CEL syntax relevant to creating expressions for these directives.
CEL সংক্রান্ত পূর্ণাঙ্গ তথ্য CEL স্পেসিফিকেশনে প্রদান করা হয়েছে।
কোয়েরি এবং মিউটেশনে পাস করা টেস্ট ভেরিয়েবল
@auth(expr) সিনট্যাক্স আপনাকে কোয়েরি এবং মিউটেশন থেকে ভেরিয়েবল অ্যাক্সেস ও পরীক্ষা করার সুযোগ দেয়।
উদাহরণস্বরূপ, আপনি vars.status ব্যবহার করে $status মতো একটি অপারেশন ভেরিয়েবল অন্তর্ভুক্ত করতে পারেন।
mutation Update($id: UUID!, $status: Any) @auth(expr: "has(vars.status)")
এক্সপ্রেশনের জন্য উপলব্ধ ডেটা: অনুরোধ, প্রতিক্রিয়া, এই
আপনি ডেটা ব্যবহার করেন:
-
@auth(expr:)এবং@check(expr:)নির্দেশাবলীতে CEL এক্সপ্রেশন ব্যবহার করে মূল্যায়ন - সার্ভার এক্সপ্রেশন ব্যবহার করে অ্যাসাইনমেন্ট,
<field>_expr.
@auth(expr:) , @check(expr:) , @refresh(onMutationExecuted:) CEL এক্সপ্রেশনগুলো নিম্নলিখিত বিষয়গুলো মূল্যায়ন করতে পারে:
-
request.operationName -
vars(request.variablesএর বিকল্প নাম) -
auth(request.authএর বিকল্প নাম)
মিউটেশন-এর ক্ষেত্রে, আপনি নিম্নলিখিতগুলির বিষয়বস্তু অ্যাক্সেস এবং নির্ধারণ করতে পারেন:
-
response(বহু-ধাপ যুক্তিতে আংশিক ফলাফল যাচাই করার জন্য)
এছাড়াও, @check(expr:) এক্সপ্রেশনগুলো মূল্যায়ন করতে পারে:
-
this(বর্তমান ফিল্ডের মান) -
response(বহু-ধাপ যুক্তিতে আংশিক ফলাফল যাচাই করার জন্য)
এবং @refresh(onMutationExecuted:) এক্সপ্রেশনগুলোর নিম্নলিখিত বাইন্ডিং রয়েছে:
-
mutation.variables -
mutation.auth
request.operationName বাইন্ডিং
request.operarationName বাইন্ডিংটি অপারেশনের ধরণ, অর্থাৎ কোয়েরি অথবা মিউটেশন, সংরক্ষণ করে।
vars বাইন্ডিং (request.vars)
vars বাইন্ডিং আপনার এক্সপ্রেশনকে কোয়েরি বা মিউটেশনে পাস করা সমস্ত ভেরিয়েবল অ্যাক্সেস করার সুযোগ দেয়।
আপনি কোনো এক্সপ্রেশনে সম্পূর্ণ request.variables.<variablename> vars.<variablename> <variablename> ব্যবহার করতে পারেন।
# The following are equivalent
mutation StringType($v: String!) @auth(expr: "vars.v == 'hello'")
mutation StringType($v: String!) @auth(expr: "request.variables.v == 'hello'")
auth বাইন্ডিং (request.auth)
Authentication আপনার ডেটাতে অ্যাক্সেসের অনুরোধকারী ব্যবহারকারীদের শনাক্ত করে এবং সেই তথ্যকে একটি বাইন্ডিং হিসেবে প্রদান করে, যার উপর ভিত্তি করে আপনি আপনার এক্সপ্রেশন তৈরি করতে পারেন।
আপনার ফিল্টার এবং এক্সপ্রেশনে, আপনি request.auth এর উপনাম (alias) হিসেবে auth ব্যবহার করতে পারেন।
অথোরাইজেশন বাইন্ডিং-এ নিম্নলিখিত তথ্য রয়েছে:
-
uid: অনুরোধকারী ব্যবহারকারীকে বরাদ্দ করা একটি অনন্য ব্যবহারকারী আইডি। -
token: Authentication দ্বারা সংগৃহীত মানগুলির একটি ম্যাপ।
auth.token এর বিষয়বস্তু সম্পর্কে আরও বিস্তারিত জানতে auth tokens-এর ডেটা দেখুন।
response বাইন্ডিং
কোনো কোয়েরি বা মিউটেশনের প্রতিক্রিয়ায় সার্ভার কর্তৃক সংগৃহীত ডেটা , ডেটা সংগ্রহের মুহূর্তেই response বাইন্ডিং-এ ধারণ করা থাকে।
অপারেশনটি অগ্রসর হওয়ার সাথে সাথে, প্রতিটি ধাপ সফলভাবে সম্পন্ন হলে, response সফলভাবে সম্পন্ন হওয়া ধাপগুলোর প্রতিক্রিয়া ডেটা অন্তর্ভুক্ত থাকে।
response বাইন্ডিংটি এর সংশ্লিষ্ট অপারেশনের গঠন অনুসারে তৈরি করা হয়, যার মধ্যে (একাধিক) নেস্টেড ফিল্ড এবং (প্রযোজ্য ক্ষেত্রে) এমবেডেড কোয়েরি অন্তর্ভুক্ত থাকে।
মনে রাখবেন যে, যখন আপনি এমবেডেড কোয়েরি রেসপন্স ডেটা অ্যাক্সেস করেন, তখন এমবেডেড কোয়েরিতে অনুরোধ করা ডেটার উপর নির্ভর করে ফিল্ডগুলিতে যেকোনো ডেটা টাইপ থাকতে পারে; যখন আপনি _insert এবং _delete এর মতো মিউটেশন ফিল্ড দ্বারা ফেরত আসা ডেটা অ্যাক্সেস করেন, তখন সেগুলিতে UUID কী, ডিলিটের সংখ্যা, নাল (null) থাকতে পারে ( মিউটেশন রেফারেন্স দেখুন)।
উদাহরণস্বরূপ:
- যে মিউটেশনে একটি এমবেডেড কোয়েরি থাকে, তার
responseবাইন্ডিং-এresponse.query.<fieldName>.<fieldName>....-এ লুকআপ ডেটা থাকে, এক্ষেত্রে,response.query.todoListএবংresponse.query.todoList.priority।
mutation CheckTodoPriority(
$uniqueListName: String!
) {
# This query is identified as `response.query`
query @check(expr: "response.query.todoList.priority == 'high'", message: "This list is not for high priority items!") {
# This field is identified as `response.query.todoList`
todoList(where: { name: $uniqueListName }) {
# This field is identified as `response.query.todoList.priority`
priority
}
}
}
- একটি বহু-ধাপের মিউটেশনে, উদাহরণস্বরূপ একাধিক
_insertফিল্ড থাকলে,responseবাইন্ডিং-এresponse.<fieldName>.<fieldName>....অংশে আংশিক ডেটা থাকে, এই ক্ষেত্রে,response.todoList_insert.id।
mutation CreateTodoListWithFirstItem(
$listName: String!,
$itemContent: String!
) @transaction {
# Step 1
todoList_insert(data: {
id_expr: "uuidV4()",
name: $listName,
})
# Step 2:
todo_insert(data: {
listId_expr: "response.todoList_insert.id" # <-- Grab the newly generated ID from the partial response so far.
content: $itemContent,
})
}
this বাঁধন
this বাইন্ডিংটি সেই ফিল্ডকে মূল্যায়ন করে, যার সাথে @check ডিরেক্টিভটি সংযুক্ত রয়েছে। একটি সাধারণ ক্ষেত্রে, আপনি একক-মানের কোয়েরির ফলাফল মূল্যায়ন করতে পারেন।
mutation UpdateMovieTitle (
$movieId: UUID!,
$newTitle: String!)
@auth(level: USER)
@transaction {
# Step 1: Query and check
query @redact {
moviePermission( # Look up a join table called MoviePermission with a compound key.
key: {movieId: $movieId, userId_expr: "auth.uid"}
) {
# Check if the user has the editor role for the movie. `this` is the string value of `role`.
# If the parent moviePermission is null, the @check will also fail automatically.
role @check(expr: "this == 'editor'", message: "You must be an editor of this movie to update title")
}
}
# Step 2: Act
movie_update(id: $movieId, data: {
title: $newTitle
})
}
যদি কোনো পূর্বপুরুষ একটি তালিকা হওয়ার কারণে ফেরত আসা ফিল্ডটি একাধিকবার আসে, তাহলে প্রতিটি মানের সাথে this বন্ধনী ব্যবহার করে প্রতিটি উপস্থিতি পরীক্ষা করা হয়।
যেকোনো প্রদত্ত পাথের ক্ষেত্রে, যদি কোনো অ্যানসেস্টর null বা [] হয়, তাহলে ফিল্ডটি অ্যাক্সেস করা যাবে না এবং সেই পাথের জন্য CEL ইভ্যালুয়েশন বাদ দেওয়া হবে। অন্য কথায়, ইভ্যালুয়েশন শুধুমাত্র তখনই সম্পন্ন হয় যখন this null বা non- null হয়, কিন্তু কখনোই undefined না।
যখন ফিল্ডটি নিজেই একটি লিস্ট বা অবজেক্ট হয়, this একই কাঠামো অনুসরণ করে (অবজেক্টের ক্ষেত্রে নির্বাচিত সমস্ত ডিসেন্ডেন্ট সহ), যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে।
mutation UpdateMovieTitle2($movieId: UUID!, $newTitle: String!) @auth(level: USER) @transaction {
# Step 1: Query and check
query {
moviePermissions( # Now we query for a list of all matching MoviePermissions.
where: {movieId: {eq: $movieId}, userId: {eq_expr: "auth.uid"}}
# This time we execute the @check on the list, so `this` is the list of objects.
# We can use the `.exists` macro to check if there is at least one matching entry.
) @check(expr: "this.exists(p, p.role == 'editor')", message: "You must be an editor of this movie to update title") {
role
}
}
# Step 2: Act
movie_update(id: $movieId, data: {
title: $newTitle
})
}
জটিল অভিব্যক্তি সিনট্যাক্স
&& এবং || অপারেটরগুলোর সমন্বয়ের মাধ্যমে আপনি আরও জটিল রাশিমালা লিখতে পারেন।
mutation UpsertUser($username: String!) @auth(expr: "(auth != null) && (vars.username == 'joe')")
নিম্নলিখিত বিভাগে সমস্ত উপলব্ধ অপারেটরগুলির বর্ণনা দেওয়া হয়েছে।
অপারেটর এবং অপারেটরের অগ্রাধিকার
অপারেটর এবং তাদের অগ্রাধিকারের ক্রম জানার জন্য নিচের সারণিটি নির্দেশিকা হিসেবে ব্যবহার করুন।
দুটি যথেচ্ছ রাশি a ও b , একটি ক্ষেত্র f , এবং একটি সূচক i দেওয়া আছে।
| অপারেটর | বর্ণনা | সহযোগীতা |
|---|---|---|
a[i] a() af | সূচক, কল, ফিল্ড অ্যাক্সেস | বাম থেকে ডানে |
!a -a | একক নেতিবাচকতা | ডান থেকে বামে |
a/ba%ba*b | গুণক অপারেটর | বাম থেকে ডানে |
a+b ab | যোগাত্মক অপারেটর | বাম থেকে ডানে |
a>b a>=b a<b a<=b | সম্পর্কীয় অপারেটর | বাম থেকে ডানে |
a in b | তালিকা বা মানচিত্রে অস্তিত্ব | বাম থেকে ডানে |
type(a) == t | প্রকার তুলনা, যেখানে t হতে পারে bool, int, float, number, string, list, map, timestamp, বা duration | বাম থেকে ডানে |
a==ba!=b | তুলনা অপারেটর | বাম থেকে ডানে |
a && b | শর্তসাপেক্ষ এবং | বাম থেকে ডানে |
a || b | শর্তসাপেক্ষ অথবা | বাম থেকে ডানে |
a ? true_value : false_value | ত্রয়ী অভিব্যক্তি | বাম থেকে ডানে |
প্রমাণীকরণ টোকেনের ডেটা
auth.token অবজেক্টটিতে নিম্নলিখিত মানগুলি থাকতে পারে:
| মাঠ | বর্ণনা |
|---|---|
email | অ্যাকাউন্টের সাথে যুক্ত ইমেল ঠিকানা, যদি থাকে। |
email_verified | যদি ব্যবহারকারী যাচাই করে থাকেন যে email ঠিকানাটিতে তার প্রবেশাধিকার আছে, তবে true । কিছু পরিষেবা প্রদানকারী তাদের মালিকানাধীন ইমেল ঠিকানাগুলো স্বয়ংক্রিয়ভাবে যাচাই করে। |
phone_number | অ্যাকাউন্টের সাথে যুক্ত ফোন নম্বর, যদি থাকে। |
name | ব্যবহারকারীর প্রদর্শিত নাম, যদি সেট করা থাকে। |
sub | ব্যবহারকারীর ফায়ারবেস ইউআইডি। এটি একটি প্রোজেক্টের মধ্যে অনন্য। |
firebase.identities | এই ব্যবহারকারীর অ্যাকাউন্টের সাথে যুক্ত সমস্ত পরিচয়ের একটি ডিকশনারি। ডিকশনারিটির কী (key) নিম্নলিখিতগুলির যেকোনো একটি হতে পারে: email , phone , google.com , facebook.com , github.com , twitter.com । ডিকশনারিটির ভ্যালু (value) হলো অ্যাকাউন্টের সাথে যুক্ত প্রতিটি আইডেন্টিটি প্রোভাইডারের জন্য অনন্য শনাক্তকারীর অ্যারে। উদাহরণস্বরূপ, auth.token.firebase.identities["google.com"][0] এ অ্যাকাউন্টের সাথে যুক্ত প্রথম গুগল ইউজার আইডি রয়েছে। |
firebase.sign_in_provider | এই টোকেনটি পেতে ব্যবহৃত সাইন-ইন প্রদানকারী। এটি নিম্নলিখিত স্ট্রিংগুলির মধ্যে একটি হতে পারে: custom , password , phone , anonymous , google.com , facebook.com , github.com , twitter.com । |
firebase.tenant | অ্যাকাউন্টের সাথে যুক্ত tenantId, যদি থাকে। উদাহরণস্বরূপ, tenant2-m6tyz |
JWT আইডি টোকেনগুলিতে অতিরিক্ত ক্ষেত্র
আপনি নিম্নলিখিত auth.token ফিল্ডগুলিও অ্যাক্সেস করতে পারেন:
| কাস্টম টোকেন দাবি | ||
|---|---|---|
alg | অ্যালগরিদম | "RS256" |
iss | ইস্যুকারী | আপনার প্রকল্পের পরিষেবা অ্যাকাউন্টের ইমেল ঠিকানা |
sub | বিষয় | আপনার প্রকল্পের পরিষেবা অ্যাকাউন্টের ইমেল ঠিকানা |
aud | দর্শক | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat | ইস্যু-সময় | ইউনিক্স ইপক থেকে বর্তমান সময়, সেকেন্ডে। |
exp | মেয়াদ শেষ হওয়ার সময় | ইউনিক্স ইপক থেকে সেকেন্ডে সেই সময়, যে সময়ে টোকেনটির মেয়াদ শেষ হয়। এটি iat এর চেয়ে সর্বোচ্চ ৩৬০০ সেকেন্ড পরে হতে পারে।দ্রষ্টব্য: এটি শুধুমাত্র কাস্টম টোকেনটির মেয়াদ শেষ হওয়ার সময় নিয়ন্ত্রণ করে। কিন্তু একবার আপনি signInWithCustomToken() ব্যবহার করে কোনো ব্যবহারকারীকে সাইন ইন করালে, তাদের সেশন বাতিল না হওয়া পর্যন্ত বা ব্যবহারকারী সাইন আউট না করা পর্যন্ত তারা ডিভাইসে সাইন ইন করা অবস্থায় থাকবে। |
<claims> (ঐচ্ছিক) | টোকেনে অন্তর্ভুক্ত করার জন্য ঐচ্ছিক কাস্টম ক্লেইম রয়েছে, যা এক্সপ্রেশনে auth.token (বা request.auth.token )-এর মাধ্যমে অ্যাক্সেস করা যায়। উদাহরণস্বরূপ, যদি আপনি adminClaim নামে একটি কাস্টম ক্লেইম তৈরি করেন, তবে আপনি auth.token.adminClaim দিয়ে এটি অ্যাক্সেস করতে পারবেন। | |
এরপর কী?
- Firebase SQL Connect provides an Admin SDK to let you perform queries and mutations from privileged environments .
- Learn about IAM security in the guide for managing services and databases .