Firebase با اجازه دادن به شما برای احراز هویت کاربران یا دستگاهها با استفاده از JSON Web Tokens (JWT) کنترل کاملی بر احراز هویت به شما میدهد. شما این نشانهها را روی سرور خود تولید میکنید، آنها را به یک دستگاه کلاینت برمیگردانید، و سپس از آنها برای احراز هویت از طریق متد signInWithCustomToken()
استفاده میکنید.
برای دستیابی به این هدف، باید یک نقطه پایانی سرور ایجاد کنید که اعتبار ورود به سیستم را بپذیرد - مانند نام کاربری و رمز عبور - و اگر اعتبارنامه معتبر باشد، یک JWT سفارشی برمیگرداند. سپس JWT سفارشی که از سرور شما بازگردانده میشود، میتواند توسط دستگاه مشتری برای احراز هویت با Firebase ( iOS ، Android ، وب ) استفاده شود. پس از احراز هویت، از این هویت هنگام دسترسی به سایر خدمات Firebase، مانند Firebase Realtime Database و Cloud Storage استفاده میشود. علاوه بر این، محتویات JWT در شی auth
در Realtime Database Security Rules و شی request.auth
در Cloud Storage Security Rules شما در دسترس خواهد بود.
میتوانید با Firebase Admin SDK یک توکن سفارشی ایجاد کنید، یا اگر سرور شما به زبانی نوشته شده است که Firebase به طور بومی پشتیبانی نمیکند، میتوانید از کتابخانه JWT شخص ثالث استفاده کنید.
قبل از شروع
توکنهای سفارشی JWTهای امضا شدهای هستند که کلید خصوصی مورد استفاده برای امضا به یک حساب سرویس Google تعلق دارد. چندین راه برای تعیین حساب سرویس Google که باید توسط Firebase Admin SDK برای امضای توکن های سفارشی استفاده شود، وجود دارد:
- استفاده از فایل JSON حساب سرویس -- این روش را می توان در هر محیطی استفاده کرد، اما از شما می خواهد که فایل JSON حساب سرویس را همراه با کد خود بسته بندی کنید. باید مراقب باشید تا اطمینان حاصل شود که فایل JSON حساب سرویس در معرض اشخاص خارجی قرار نمی گیرد.
- اجازه دادن به Admin SDK برای کشف یک حساب سرویس -- این روش را می توان در محیط های مدیریت شده توسط Google مانند Google Cloud Functions و App Engine استفاده کرد. ممکن است مجبور شوید برخی از مجوزهای اضافی را از طریق کنسول Google Cloud پیکربندی کنید.
- استفاده از شناسه حساب سرویس -- هنگامی که در یک محیط مدیریت شده توسط Google استفاده می شود، این روش با استفاده از کلید حساب سرویس مشخص شده، نشانه ها را امضا می کند. با این حال، از یک سرویس وب راه دور استفاده می کند، و ممکن است مجبور شوید مجوزهای اضافی را برای این حساب سرویس از طریق کنسول Google Cloud پیکربندی کنید.
استفاده از فایل JSON حساب سرویس
فایلهای JSON حساب سرویس حاوی تمام اطلاعات مربوط به حسابهای سرویس (از جمله کلید خصوصی RSA) هستند. آنها را می توان از کنسول Firebase دانلود کرد. دستورالعملهای راهاندازی Admin SDK را برای اطلاعات بیشتر در مورد نحوه راهاندازی اولیه SDK مدیریت با یک فایل JSON حساب سرویس دنبال کنید.
این روش مقداردهی اولیه برای طیف وسیعی از استقرار Admin SDK مناسب است. همچنین Admin SDK را قادر میسازد تا توکنهای سفارشی را به صورت محلی ایجاد و امضا کند، بدون اینکه تماس API از راه دور برقرار کند. اشکال اصلی این روش این است که شما را ملزم می کند یک فایل JSON حساب سرویس را به همراه کد خود بسته بندی کنید. همچنین توجه داشته باشید که کلید خصوصی در فایل JSON حساب سرویس، اطلاعات حساسی است و باید مراقب محرمانه ماندن آن بود. به طور خاص، از افزودن فایلهای JSON حساب سرویس به کنترل نسخه عمومی خودداری کنید.
اجازه دادن به Admin SDK یک حساب سرویس را کشف کند
اگر کد شما در محیطی که توسط Google مدیریت میشود مستقر شده است، Admin SDK میتواند به طور خودکار ابزاری را برای امضای نشانههای سفارشی کشف کند:
اگر کد شما در محیط استاندارد App Engine برای Java، Python یا Go مستقر شده است، Admin SDK میتواند از سرویس App Identity موجود در آن محیط برای امضای توکنهای سفارشی استفاده کند. سرویس App Identity داده ها را با استفاده از حساب سرویسی که توسط Google App Engine برای برنامه شما ارائه شده است امضا می کند.
اگر کد شما در محیط مدیریت شده دیگری (به عنوان مثال Google Cloud Functions، Google Compute Engine) مستقر شده باشد، Firebase Admin SDK می تواند به طور خودکار یک رشته شناسه حساب سرویس را از سرور ابرداده محلی پیدا کند. سپس شناسه حساب سرویس کشف شده همراه با سرویس IAM برای امضای توکن ها از راه دور استفاده می شود.
برای استفاده از این روشهای امضا، SDK را با اطلاعات کاربری پیشفرض Google Application مقداردهی اولیه کنید و رشته ID حساب سرویس را مشخص نکنید:
initializeApp();
FirebaseApp.initializeApp();
default_app = firebase_admin.initialize_app()
app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
log.Fatalf("error initializing app: %v\n", err)
}
FirebaseApp.Create();
برای آزمایش همان کد به صورت محلی، یک فایل JSON حساب سرویس را دانلود کنید و متغیر محیطی GOOGLE_APPLICATION_CREDENTIALS
را تنظیم کنید تا به آن اشاره کند.
اگر Firebase Admin SDK باید رشته ID حساب سرویس را پیدا کند، زمانی که کد شما برای اولین بار یک توکن سفارشی ایجاد میکند، این کار را انجام میدهد. نتیجه ذخیره میشود و برای عملیات امضای نشانههای بعدی مجدداً استفاده میشود. شناسه حساب سرویس کشف شده خودکار معمولاً یکی از حسابهای خدمات پیشفرض ارائه شده توسط Google Cloud است:
درست مانند شناسههای حساب سرویس که بهصراحت مشخص شدهاند، شناسههای حساب سرویس با کشف خودکار باید مجوز iam.serviceAccounts.signBlob
را داشته باشند تا ایجاد توکن سفارشی کار کند. برای اعطای مجوزهای لازم به حسابهای سرویس پیشفرض، ممکن است مجبور شوید از IAM و بخش سرپرست کنسول Google Cloud استفاده کنید. برای جزئیات بیشتر به بخش عیب یابی زیر مراجعه کنید.
با استفاده از شناسه حساب سرویس
برای حفظ سازگاری بین بخشهای مختلف برنامهتان، میتوانید شناسه حساب سرویسی را مشخص کنید که کلیدهای آن برای امضای نشانهها هنگام اجرا در یک محیط تحت مدیریت Google مورد استفاده قرار میگیرد. این میتواند خطمشیهای IAM را سادهتر و ایمنتر کند و از گنجاندن فایل JSON حساب سرویس در کد خود اجتناب کند.
شناسه حساب سرویس را می توان در کنسول Google Cloud یا در قسمت client_email
یک فایل JSON حساب سرویس دانلود شده پیدا کرد. شناسههای حساب سرویس، آدرسهای ایمیلی هستند که قالب زیر را دارند: <client-id>@<project-id>.iam.gserviceaccount.com
. آنها حسابهای سرویس را در پروژههای Firebase و Google Cloud بهطور منحصربهفرد شناسایی میکنند.
برای ایجاد توکن های سفارشی با استفاده از شناسه حساب سرویس جداگانه، SDK را مطابق شکل زیر مقداردهی اولیه کنید:
initializeApp({
serviceAccountId: 'my-client-id@my-project-id.iam.gserviceaccount.com',
});
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(GoogleCredentials.getApplicationDefault())
.setServiceAccountId("my-client-id@my-project-id.iam.gserviceaccount.com")
.build();
FirebaseApp.initializeApp(options);
options = {
'serviceAccountId': 'my-client-id@my-project-id.iam.gserviceaccount.com',
}
firebase_admin.initialize_app(options=options)
conf := &firebase.Config{
ServiceAccountID: "my-client-id@my-project-id.iam.gserviceaccount.com",
}
app, err := firebase.NewApp(context.Background(), conf)
if err != nil {
log.Fatalf("error initializing app: %v\n", err)
}
FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.GetApplicationDefault(),
ServiceAccountId = "my-client-id@my-project-id.iam.gserviceaccount.com",
});
شناسههای حساب سرویس اطلاعات حساسی نیستند و بنابراین قرار گرفتن در معرض آنها بیاهمیت است. با این حال، برای امضای توکنهای سفارشی با حساب سرویس مشخصشده، Firebase Admin SDK باید یک سرویس راه دور را فراخوانی کند. علاوه بر این، باید مطمئن شوید که حساب سرویس Admin SDK که برای برقراری این تماس از آن استفاده میکند - معمولاً {project-name}@appspot.gserviceaccount.com
- دارای مجوز iam.serviceAccounts.signBlob
است. برای جزئیات بیشتر به بخش عیب یابی زیر مراجعه کنید.
با استفاده از Firebase Admin SDK توکن های سفارشی ایجاد کنید
Firebase Admin SDK دارای یک روش داخلی برای ایجاد توکن های سفارشی است. حداقل باید یک uid
ارائه کنید که می تواند هر رشته ای باشد اما باید کاربر یا دستگاهی را که احراز هویت می کنید مشخص کند. این توکن ها پس از یک ساعت منقضی می شوند.
const uid = 'some-uid';
getAuth()
.createCustomToken(uid)
.then((customToken) => {
// Send token back to client
})
.catch((error) => {
console.log('Error creating custom token:', error);
});
String uid = "some-uid";
String customToken = FirebaseAuth.getInstance().createCustomToken(uid);
// Send token back to client
uid = 'some-uid'
custom_token = auth.create_custom_token(uid)
client, err := app.Auth(context.Background())
if err != nil {
log.Fatalf("error getting Auth client: %v\n", err)
}
token, err := client.CustomToken(ctx, "some-uid")
if err != nil {
log.Fatalf("error minting custom token: %v\n", err)
}
log.Printf("Got custom token: %v\n", token)
var uid = "some-uid";
string customToken = await FirebaseAuth.DefaultInstance.CreateCustomTokenAsync(uid);
// Send token back to client
همچنین می توانید به صورت اختیاری ادعاهای اضافی را برای گنجاندن در توکن سفارشی مشخص کنید. به عنوان مثال، در زیر، یک فیلد premiumAccount
به توکن سفارشی اضافه شده است که در اشیاء auth
/ request.auth
در قوانین امنیتی شما در دسترس خواهد بود:
const userId = 'some-uid';
const additionalClaims = {
premiumAccount: true,
};
getAuth()
.createCustomToken(userId, additionalClaims)
.then((customToken) => {
// Send token back to client
})
.catch((error) => {
console.log('Error creating custom token:', error);
});
String uid = "some-uid";
Map<String, Object> additionalClaims = new HashMap<String, Object>();
additionalClaims.put("premiumAccount", true);
String customToken = FirebaseAuth.getInstance()
.createCustomToken(uid, additionalClaims);
// Send token back to client
uid = 'some-uid'
additional_claims = {
'premiumAccount': True
}
custom_token = auth.create_custom_token(uid, additional_claims)
client, err := app.Auth(context.Background())
if err != nil {
log.Fatalf("error getting Auth client: %v\n", err)
}
claims := map[string]interface{}{
"premiumAccount": true,
}
token, err := client.CustomTokenWithClaims(ctx, "some-uid", claims)
if err != nil {
log.Fatalf("error minting custom token: %v\n", err)
}
log.Printf("Got custom token: %v\n", token)
var uid = "some-uid";
var additionalClaims = new Dictionary<string, object>()
{
{ "premiumAccount", true },
};
string customToken = await FirebaseAuth.DefaultInstance
.CreateCustomTokenAsync(uid, additionalClaims);
// Send token back to client
نامهای رمز سفارشی رزرو شده
با استفاده از توکن های سفارشی روی مشتریان وارد شوید
پس از ایجاد یک توکن سفارشی، باید آن را به برنامه مشتری خود ارسال کنید. برنامه مشتری با فراخوانی signInWithCustomToken()
با توکن سفارشی احراز هویت میشود:
هدف-C
[[FIRAuth auth] signInWithCustomToken:customToken
completion:^(FIRAuthDataResult * _Nullable authResult,
NSError * _Nullable error) {
// ...
}];
سویفت
Auth.auth().signIn(withCustomToken: customToken ?? "") { user, error in
// ...
}
mAuth.signInWithCustomToken(mCustomToken)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCustomToken:success");
FirebaseUser user = mAuth.getCurrentUser();
updateUI(user);
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCustomToken:failure", task.getException());
Toast.makeText(CustomAuthActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
updateUI(null);
}
}
});
auth.SignInWithCustomTokenAsync(custom_token).ContinueWith(task => {
if (task.IsCanceled) {
Debug.LogError("SignInWithCustomTokenAsync was canceled.");
return;
}
if (task.IsFaulted) {
Debug.LogError("SignInWithCustomTokenAsync encountered an error: " + task.Exception);
return;
}
Firebase.Auth.AuthResult result = task.Result;
Debug.LogFormat("User signed in successfully: {0} ({1})",
result.User.DisplayName, result.User.UserId);
});
firebase::Future<firebase::auth::AuthResult> result =
auth->SignInWithCustomToken(custom_token);
firebase.auth().signInWithCustomToken(token)
.then((userCredential) => {
// Signed in
var user = userCredential.user;
// ...
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
import { getAuth, signInWithCustomToken } from "firebase/auth";
const auth = getAuth();
signInWithCustomToken(auth, token)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
// ...
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
// ...
});
اگر احراز هویت با موفقیت انجام شود، کاربر شما اکنون با حساب مشخص شده توسط uid
موجود در کد سفارشی وارد برنامه مشتری شما خواهد شد. اگر آن حساب قبلا وجود نداشت، یک رکورد برای آن کاربر ایجاد می شود.
مانند سایر روشهای ورود به سیستم (مانند signInWithEmailAndPassword()
و signInWithCredential()
) شی auth
در Realtime Database Security Rules و شی request.auth
در Cloud Storage Security Rules شما با uid
کاربر پر میشود. در این حالت، uid
همانی خواهد بود که هنگام تولید توکن سفارشی مشخص کردهاید.
{
"rules": {
"adminContent": {
".read": "auth.uid === 'some-uid'"
}
}
}
service firebase.storage {
match /b/<your-firebase-storage-bucket>/o {
match /adminContent/{filename} {
allow read, write: if request.auth != null && request.auth.uid == "some-uid";
}
}
}
اگر توکن سفارشی حاوی ادعاهای اضافی باشد، میتوان آنها را از auth.token
( Firebase Realtime Database ) یا شی request.auth.token
( Cloud Storage ) در قوانین شما ارجاع داد:
{
"rules": {
"premiumContent": {
".read": "auth.token.premiumAccount === true"
}
}
}
service firebase.storage {
match /b/<your-firebase-storage-bucket>/o {
match /premiumContent/{filename} {
allow read, write: if request.auth.token.premiumAccount == true;
}
}
}
با استفاده از یک کتابخانه JWT شخص ثالث، توکن های سفارشی ایجاد کنید
اگر باطن شما به زبانی است که Firebase Admin SDK رسمی ندارد، همچنان می توانید به صورت دستی توکن های سفارشی ایجاد کنید. ابتدا یک کتابخانه JWT شخص ثالث برای زبان خود پیدا کنید . سپس، از آن کتابخانه JWT برای ایجاد یک JWT که شامل ادعاهای زیر است استفاده کنید:
ادعاهای توکن سفارشی | ||
---|---|---|
alg | الگوریتم | "RS256" |
iss | صادر کننده | آدرس ایمیل حساب سرویس پروژه شما |
sub | موضوع | آدرس ایمیل حساب سرویس پروژه شما |
aud | مخاطب | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat | صادر شده در زمان | زمان فعلی، در ثانیه از دوران یونیکس |
exp | زمان انقضا | زمان، بر حسب ثانیه از دوره یونیکس، که در آن توکن منقضی میشود. می تواند حداکثر 3600 ثانیه دیرتر از iat باشد.توجه: این فقط زمانی را کنترل می کند که خود توکن سفارشی منقضی شود. اما هنگامی که کاربر را با استفاده از signInWithCustomToken() وارد سیستم کردید، تا زمانی که جلسه آنها باطل شود یا کاربر از سیستم خارج نشود، وارد دستگاه میشوند. |
uid | شناسه منحصربهفرد کاربری که وارد سیستم شده است باید یک رشته، بین 1 تا 128 کاراکتر و شامل باشد. uid های کوتاهتر عملکرد بهتری را ارائه می دهند. | |
claims (اختیاری) | ادعاهای سفارشی اختیاری برای گنجاندن متغیرهای auth / request.auth در قوانین امنیتی |
در اینجا چند نمونه پیاده سازی از نحوه ایجاد توکن های سفارشی در زبان های مختلف که Firebase Admin SDK پشتیبانی نمی کند آورده شده است:
استفاده از php-jwt
:
// Requires: composer require firebase/php-jwt
use Firebase\JWT\JWT;
// Get your service account's email address and private key from the JSON key file
$service_account_email = "abc-123@a-b-c-123.iam.gserviceaccount.com";
$private_key = "-----BEGIN PRIVATE KEY-----...";
function create_custom_token($uid, $is_premium_account) {
global $service_account_email, $private_key;
$now_seconds = time();
$payload = array(
"iss" => $service_account_email,
"sub" => $service_account_email,
"aud" => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
"iat" => $now_seconds,
"exp" => $now_seconds+(60*60), // Maximum expiration time is one hour
"uid" => $uid,
"claims" => array(
"premium_account" => $is_premium_account
)
);
return JWT::encode($payload, $private_key, "RS256");
}
با استفاده از ruby-jwt
:
require "jwt"
# Get your service account's email address and private key from the JSON key file
$service_account_email = "service-account@my-project-abc123.iam.gserviceaccount.com"
$private_key = OpenSSL::PKey::RSA.new "-----BEGIN PRIVATE KEY-----\n..."
def create_custom_token(uid, is_premium_account)
now_seconds = Time.now.to_i
payload = {:iss => $service_account_email,
:sub => $service_account_email,
:aud => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
:iat => now_seconds,
:exp => now_seconds+(60*60), # Maximum expiration time is one hour
:uid => uid,
:claims => {:premium_account => is_premium_account}}
JWT.encode payload, $private_key, "RS256"
end
پس از ایجاد توکن سفارشی، آن را به برنامه مشتری خود ارسال کنید تا از آن برای احراز هویت با Firebase استفاده کنید. برای نحوه انجام این کار به نمونه کدهای بالا مراجعه کنید.
عیب یابی
این بخش برخی از مشکلات رایجی که توسعه دهندگان ممکن است در هنگام ایجاد توکن های سفارشی با آن مواجه شوند و نحوه حل آنها را تشریح می کند.
IAM API فعال نیست
اگر شناسه حساب سرویس را برای امضای توکن ها مشخص می کنید، ممکن است با خطای زیر مواجه شوید:
Identity and Access Management (IAM) API has not been used in project 1234567890 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/iam.googleapis.com/overview?project=1234567890 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
Firebase Admin SDK از IAM API برای امضای توکن ها استفاده می کند. این خطا نشان می دهد که IAM API در حال حاضر برای پروژه Firebase شما فعال نیست. پیوند موجود در پیام خطا را در یک مرورگر وب باز کنید و روی دکمه "فعال کردن API" کلیک کنید تا آن را برای پروژه خود فعال کنید.
حساب سرویس مجوزهای لازم را ندارد
اگر حساب سرویس Firebase Admin SDK بدون مجوز iam.serviceAccounts.signBlob
اجرا میشود، ممکن است پیام خطایی مانند زیر دریافت کنید:
Permission iam.serviceAccounts.signBlob is required to perform this operation on service account projects/-/serviceAccounts/{your-service-account-id}.
ساده ترین راه برای حل این مشکل، اعطای نقش IAM «خلق رمز حساب سرویس» به حساب سرویس مورد نظر، معمولاً {project-name}@appspot.gserviceaccount.com
است:
- صفحه IAM و admin را در کنسول Google Cloud باز کنید.
- پروژه خود را انتخاب کنید و روی "ادامه" کلیک کنید.
- روی نماد ویرایش مربوط به حساب سرویسی که می خواهید به روز کنید کلیک کنید.
- روی «افزودن نقش دیگر» کلیک کنید.
- "Service Account Token Creator" را در فیلتر جستجو تایپ کنید و آن را از نتایج انتخاب کنید.
- برای تایید اعطای نقش روی "ذخیره" کلیک کنید.
برای جزئیات بیشتر در مورد این فرآیند به مستندات IAM مراجعه کنید، یا یاد بگیرید که چگونه نقشهای بهروزرسانی را با استفاده از ابزارهای خط فرمان gcloud انجام دهید.
حساب سرویس تعیین نشد
اگر پیام خطایی مشابه زیر دریافت کردید، Firebase Admin SDK به درستی مقداردهی اولیه نشده است.
Failed to determine service account ID. Initialize the SDK with service account credentials or specify a service account ID with iam.serviceAccounts.signBlob permission.
اگر برای کشف خودکار شناسه حساب سرویس به SDK متکی هستید، مطمئن شوید که کد در یک محیط مدیریت شده Google با سرور ابرداده مستقر شده است. در غیر این صورت، حتماً فایل JSON حساب سرویس یا شناسه حساب سرویس را در مقداردهی اولیه SDK مشخص کنید.
، Firebase با اجازه دادن به شما برای احراز هویت کاربران یا دستگاهها با استفاده از JSON Web Tokens (JWT) کنترل کاملی بر احراز هویت به شما میدهد. شما این نشانهها را روی سرور خود تولید میکنید، آنها را به یک دستگاه کلاینت برمیگردانید، و سپس از آنها برای احراز هویت از طریق متد signInWithCustomToken()
استفاده میکنید.
برای دستیابی به این هدف، باید یک نقطه پایانی سرور ایجاد کنید که اعتبار ورود به سیستم را بپذیرد - مانند نام کاربری و رمز عبور - و اگر اعتبارنامه معتبر باشد، یک JWT سفارشی برمیگرداند. سپس JWT سفارشی که از سرور شما بازگردانده میشود، میتواند توسط دستگاه مشتری برای احراز هویت با Firebase ( iOS ، Android ، وب ) استفاده شود. پس از احراز هویت، از این هویت هنگام دسترسی به سایر خدمات Firebase، مانند Firebase Realtime Database و Cloud Storage استفاده میشود. علاوه بر این، محتویات JWT در شی auth
در Realtime Database Security Rules و شی request.auth
در Cloud Storage Security Rules شما در دسترس خواهد بود.
میتوانید با Firebase Admin SDK یک توکن سفارشی ایجاد کنید، یا اگر سرور شما به زبانی نوشته شده است که Firebase به طور بومی پشتیبانی نمیکند، میتوانید از کتابخانه JWT شخص ثالث استفاده کنید.
قبل از شروع
توکنهای سفارشی JWTهای امضا شدهای هستند که کلید خصوصی مورد استفاده برای امضا به یک حساب سرویس Google تعلق دارد. چندین راه برای تعیین حساب سرویس Google که باید توسط Firebase Admin SDK برای امضای توکن های سفارشی استفاده شود، وجود دارد:
- استفاده از فایل JSON حساب سرویس -- این روش را می توان در هر محیطی استفاده کرد، اما از شما می خواهد که فایل JSON حساب سرویس را همراه با کد خود بسته بندی کنید. باید مراقب باشید تا اطمینان حاصل شود که فایل JSON حساب سرویس در معرض اشخاص خارجی قرار نمی گیرد.
- اجازه دادن به Admin SDK برای کشف یک حساب سرویس -- این روش را می توان در محیط های مدیریت شده توسط Google مانند Google Cloud Functions و App Engine استفاده کرد. ممکن است مجبور شوید برخی از مجوزهای اضافی را از طریق کنسول Google Cloud پیکربندی کنید.
- استفاده از شناسه حساب سرویس -- هنگامی که در یک محیط مدیریت شده توسط Google استفاده می شود، این روش با استفاده از کلید حساب سرویس مشخص شده، نشانه ها را امضا می کند. با این حال، از یک سرویس وب راه دور استفاده می کند، و ممکن است مجبور شوید مجوزهای اضافی را برای این حساب سرویس از طریق کنسول Google Cloud پیکربندی کنید.
استفاده از فایل JSON حساب سرویس
فایلهای JSON حساب سرویس حاوی تمام اطلاعات مربوط به حسابهای سرویس (از جمله کلید خصوصی RSA) هستند. آنها را می توان از کنسول Firebase دانلود کرد. دستورالعملهای راهاندازی Admin SDK را برای اطلاعات بیشتر در مورد نحوه راهاندازی اولیه SDK مدیریت با یک فایل JSON حساب سرویس دنبال کنید.
این روش مقداردهی اولیه برای طیف وسیعی از استقرار Admin SDK مناسب است. همچنین Admin SDK را قادر میسازد تا توکنهای سفارشی را به صورت محلی ایجاد و امضا کند، بدون اینکه تماس API از راه دور برقرار کند. اشکال اصلی این روش این است که شما را ملزم می کند یک فایل JSON حساب سرویس را به همراه کد خود بسته بندی کنید. همچنین توجه داشته باشید که کلید خصوصی در فایل JSON حساب سرویس، اطلاعات حساسی است و باید مراقب محرمانه ماندن آن بود. به طور خاص، از افزودن فایلهای JSON حساب سرویس به کنترل نسخه عمومی خودداری کنید.
اجازه دادن به Admin SDK یک حساب سرویس را کشف کند
اگر کد شما در محیطی که توسط Google مدیریت میشود مستقر شده است، Admin SDK میتواند به طور خودکار ابزاری را برای امضای نشانههای سفارشی کشف کند:
اگر کد شما در محیط استاندارد App Engine برای Java، Python یا Go مستقر شده است، Admin SDK میتواند از سرویس App Identity موجود در آن محیط برای امضای توکنهای سفارشی استفاده کند. سرویس App Identity داده ها را با استفاده از حساب سرویسی که توسط Google App Engine برای برنامه شما ارائه شده است امضا می کند.
اگر کد شما در محیط مدیریت شده دیگری (به عنوان مثال Google Cloud Functions، Google Compute Engine) مستقر شده باشد، Firebase Admin SDK می تواند به طور خودکار یک رشته شناسه حساب سرویس را از سرور ابرداده محلی پیدا کند. سپس شناسه حساب سرویس کشف شده همراه با سرویس IAM برای امضای توکن ها از راه دور استفاده می شود.
برای استفاده از این روشهای امضا، SDK را با اطلاعات کاربری پیشفرض Google Application مقداردهی اولیه کنید و رشته ID حساب سرویس را مشخص نکنید:
initializeApp();
FirebaseApp.initializeApp();
default_app = firebase_admin.initialize_app()
app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
log.Fatalf("error initializing app: %v\n", err)
}
FirebaseApp.Create();
برای آزمایش همان کد به صورت محلی، یک فایل JSON حساب سرویس را دانلود کنید و متغیر محیطی GOOGLE_APPLICATION_CREDENTIALS
را تنظیم کنید تا به آن اشاره کند.
اگر Firebase Admin SDK باید رشته ID حساب سرویس را پیدا کند، زمانی که کد شما برای اولین بار یک توکن سفارشی ایجاد میکند، این کار را انجام میدهد. نتیجه ذخیره میشود و برای عملیات امضای نشانههای بعدی مجدداً استفاده میشود. شناسه حساب سرویس کشف شده خودکار معمولاً یکی از حسابهای خدمات پیشفرض ارائه شده توسط Google Cloud است:
درست مانند شناسههای حساب سرویس که بهصراحت مشخص شدهاند، شناسههای حساب سرویس با کشف خودکار باید مجوز iam.serviceAccounts.signBlob
را داشته باشند تا ایجاد توکن سفارشی کار کند. برای اعطای مجوزهای لازم به حسابهای سرویس پیشفرض، ممکن است مجبور شوید از IAM و بخش سرپرست کنسول Google Cloud استفاده کنید. برای جزئیات بیشتر به بخش عیب یابی زیر مراجعه کنید.
با استفاده از شناسه حساب سرویس
برای حفظ سازگاری بین بخشهای مختلف برنامهتان، میتوانید شناسه حساب سرویسی را مشخص کنید که کلیدهای آن برای امضای نشانهها هنگام اجرا در یک محیط تحت مدیریت Google مورد استفاده قرار میگیرد. این میتواند خطمشیهای IAM را سادهتر و ایمنتر کند و از گنجاندن فایل JSON حساب سرویس در کد خود اجتناب کند.
شناسه حساب سرویس را می توان در کنسول Google Cloud یا در قسمت client_email
یک فایل JSON حساب سرویس دانلود شده پیدا کرد. شناسههای حساب سرویس، آدرسهای ایمیلی هستند که قالب زیر را دارند: <client-id>@<project-id>.iam.gserviceaccount.com
. آنها حسابهای سرویس را در پروژههای Firebase و Google Cloud بهطور منحصربهفرد شناسایی میکنند.
برای ایجاد توکن های سفارشی با استفاده از شناسه حساب سرویس جداگانه، SDK را مطابق شکل زیر مقداردهی اولیه کنید:
initializeApp({
serviceAccountId: 'my-client-id@my-project-id.iam.gserviceaccount.com',
});
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(GoogleCredentials.getApplicationDefault())
.setServiceAccountId("my-client-id@my-project-id.iam.gserviceaccount.com")
.build();
FirebaseApp.initializeApp(options);
options = {
'serviceAccountId': 'my-client-id@my-project-id.iam.gserviceaccount.com',
}
firebase_admin.initialize_app(options=options)
conf := &firebase.Config{
ServiceAccountID: "my-client-id@my-project-id.iam.gserviceaccount.com",
}
app, err := firebase.NewApp(context.Background(), conf)
if err != nil {
log.Fatalf("error initializing app: %v\n", err)
}
FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.GetApplicationDefault(),
ServiceAccountId = "my-client-id@my-project-id.iam.gserviceaccount.com",
});
شناسههای حساب سرویس اطلاعات حساسی نیستند و بنابراین قرار گرفتن در معرض آنها بیاهمیت است. با این حال، برای امضای توکنهای سفارشی با حساب سرویس مشخصشده، Firebase Admin SDK باید یک سرویس راه دور را فراخوانی کند. علاوه بر این، باید مطمئن شوید که حساب سرویس Admin SDK که برای برقراری این تماس از آن استفاده میکند - معمولاً {project-name}@appspot.gserviceaccount.com
- دارای مجوز iam.serviceAccounts.signBlob
است. برای جزئیات بیشتر به بخش عیب یابی زیر مراجعه کنید.
با استفاده از Firebase Admin SDK توکن های سفارشی ایجاد کنید
Firebase Admin SDK دارای یک روش داخلی برای ایجاد توکن های سفارشی است. حداقل باید یک uid
ارائه کنید که می تواند هر رشته ای باشد اما باید کاربر یا دستگاهی را که احراز هویت می کنید مشخص کند. این توکن ها پس از یک ساعت منقضی می شوند.
const uid = 'some-uid';
getAuth()
.createCustomToken(uid)
.then((customToken) => {
// Send token back to client
})
.catch((error) => {
console.log('Error creating custom token:', error);
});
String uid = "some-uid";
String customToken = FirebaseAuth.getInstance().createCustomToken(uid);
// Send token back to client
uid = 'some-uid'
custom_token = auth.create_custom_token(uid)
client, err := app.Auth(context.Background())
if err != nil {
log.Fatalf("error getting Auth client: %v\n", err)
}
token, err := client.CustomToken(ctx, "some-uid")
if err != nil {
log.Fatalf("error minting custom token: %v\n", err)
}
log.Printf("Got custom token: %v\n", token)
var uid = "some-uid";
string customToken = await FirebaseAuth.DefaultInstance.CreateCustomTokenAsync(uid);
// Send token back to client
همچنین می توانید به صورت اختیاری ادعاهای اضافی را برای گنجاندن در توکن سفارشی مشخص کنید. به عنوان مثال، در زیر، یک فیلد premiumAccount
به توکن سفارشی اضافه شده است که در اشیاء auth
/ request.auth
در قوانین امنیتی شما در دسترس خواهد بود:
const userId = 'some-uid';
const additionalClaims = {
premiumAccount: true,
};
getAuth()
.createCustomToken(userId, additionalClaims)
.then((customToken) => {
// Send token back to client
})
.catch((error) => {
console.log('Error creating custom token:', error);
});
String uid = "some-uid";
Map<String, Object> additionalClaims = new HashMap<String, Object>();
additionalClaims.put("premiumAccount", true);
String customToken = FirebaseAuth.getInstance()
.createCustomToken(uid, additionalClaims);
// Send token back to client
uid = 'some-uid'
additional_claims = {
'premiumAccount': True
}
custom_token = auth.create_custom_token(uid, additional_claims)
client, err := app.Auth(context.Background())
if err != nil {
log.Fatalf("error getting Auth client: %v\n", err)
}
claims := map[string]interface{}{
"premiumAccount": true,
}
token, err := client.CustomTokenWithClaims(ctx, "some-uid", claims)
if err != nil {
log.Fatalf("error minting custom token: %v\n", err)
}
log.Printf("Got custom token: %v\n", token)
var uid = "some-uid";
var additionalClaims = new Dictionary<string, object>()
{
{ "premiumAccount", true },
};
string customToken = await FirebaseAuth.DefaultInstance
.CreateCustomTokenAsync(uid, additionalClaims);
// Send token back to client
نامهای رمز سفارشی رزرو شده
با استفاده از توکن های سفارشی روی مشتریان وارد شوید
پس از ایجاد یک توکن سفارشی، باید آن را به برنامه مشتری خود ارسال کنید. برنامه مشتری با فراخوانی signInWithCustomToken()
با توکن سفارشی احراز هویت میشود:
هدف-C
[[FIRAuth auth] signInWithCustomToken:customToken
completion:^(FIRAuthDataResult * _Nullable authResult,
NSError * _Nullable error) {
// ...
}];
سویفت
Auth.auth().signIn(withCustomToken: customToken ?? "") { user, error in
// ...
}
mAuth.signInWithCustomToken(mCustomToken)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCustomToken:success");
FirebaseUser user = mAuth.getCurrentUser();
updateUI(user);
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCustomToken:failure", task.getException());
Toast.makeText(CustomAuthActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
updateUI(null);
}
}
});
auth.SignInWithCustomTokenAsync(custom_token).ContinueWith(task => {
if (task.IsCanceled) {
Debug.LogError("SignInWithCustomTokenAsync was canceled.");
return;
}
if (task.IsFaulted) {
Debug.LogError("SignInWithCustomTokenAsync encountered an error: " + task.Exception);
return;
}
Firebase.Auth.AuthResult result = task.Result;
Debug.LogFormat("User signed in successfully: {0} ({1})",
result.User.DisplayName, result.User.UserId);
});
firebase::Future<firebase::auth::AuthResult> result =
auth->SignInWithCustomToken(custom_token);
firebase.auth().signInWithCustomToken(token)
.then((userCredential) => {
// Signed in
var user = userCredential.user;
// ...
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
import { getAuth, signInWithCustomToken } from "firebase/auth";
const auth = getAuth();
signInWithCustomToken(auth, token)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
// ...
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
// ...
});
اگر احراز هویت با موفقیت انجام شود، کاربر شما اکنون با حساب مشخص شده توسط uid
موجود در کد سفارشی وارد برنامه مشتری شما خواهد شد. اگر آن حساب قبلا وجود نداشت، یک رکورد برای آن کاربر ایجاد می شود.
مانند سایر روشهای ورود به سیستم (مانند signInWithEmailAndPassword()
و signInWithCredential()
) شی auth
در Realtime Database Security Rules و شی request.auth
در Cloud Storage Security Rules شما با uid
کاربر پر میشود. در این حالت، uid
همانی خواهد بود که هنگام تولید توکن سفارشی مشخص کردهاید.
{
"rules": {
"adminContent": {
".read": "auth.uid === 'some-uid'"
}
}
}
service firebase.storage {
match /b/<your-firebase-storage-bucket>/o {
match /adminContent/{filename} {
allow read, write: if request.auth != null && request.auth.uid == "some-uid";
}
}
}
اگر توکن سفارشی حاوی ادعاهای اضافی باشد، میتوان آنها را از auth.token
( Firebase Realtime Database ) یا شی request.auth.token
( Cloud Storage ) در قوانین شما ارجاع داد:
{
"rules": {
"premiumContent": {
".read": "auth.token.premiumAccount === true"
}
}
}
service firebase.storage {
match /b/<your-firebase-storage-bucket>/o {
match /premiumContent/{filename} {
allow read, write: if request.auth.token.premiumAccount == true;
}
}
}
با استفاده از یک کتابخانه JWT شخص ثالث، توکن های سفارشی ایجاد کنید
اگر باطن شما به زبانی است که Firebase Admin SDK رسمی ندارد، همچنان می توانید به صورت دستی توکن های سفارشی ایجاد کنید. ابتدا یک کتابخانه JWT شخص ثالث برای زبان خود پیدا کنید . سپس، از آن کتابخانه JWT برای ایجاد یک JWT که شامل ادعاهای زیر است استفاده کنید:
ادعاهای توکن سفارشی | ||
---|---|---|
alg | الگوریتم | "RS256" |
iss | صادر کننده | آدرس ایمیل حساب سرویس پروژه شما |
sub | موضوع | آدرس ایمیل حساب سرویس پروژه شما |
aud | مخاطب | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat | صادر شده در زمان | زمان فعلی، در ثانیه از دوران یونیکس |
exp | زمان انقضا | زمان، بر حسب ثانیه از دوره یونیکس، که در آن توکن منقضی میشود. می تواند حداکثر 3600 ثانیه دیرتر از iat باشد.توجه: این فقط زمانی را کنترل می کند که خود توکن سفارشی منقضی شود. اما هنگامی که کاربر را با استفاده از signInWithCustomToken() وارد سیستم کردید، تا زمانی که جلسه آنها باطل شود یا کاربر از سیستم خارج نشود، وارد دستگاه میشوند. |
uid | شناسه منحصربهفرد کاربری که وارد سیستم شده است باید یک رشته، بین 1 تا 128 کاراکتر و شامل باشد. uid های کوتاهتر عملکرد بهتری را ارائه می دهند. | |
claims (اختیاری) | ادعاهای سفارشی اختیاری برای گنجاندن متغیرهای auth / request.auth در قوانین امنیتی |
در اینجا چند نمونه پیاده سازی از نحوه ایجاد توکن های سفارشی در زبان های مختلف که Firebase Admin SDK پشتیبانی نمی کند آورده شده است:
استفاده از php-jwt
:
// Requires: composer require firebase/php-jwt
use Firebase\JWT\JWT;
// Get your service account's email address and private key from the JSON key file
$service_account_email = "abc-123@a-b-c-123.iam.gserviceaccount.com";
$private_key = "-----BEGIN PRIVATE KEY-----...";
function create_custom_token($uid, $is_premium_account) {
global $service_account_email, $private_key;
$now_seconds = time();
$payload = array(
"iss" => $service_account_email,
"sub" => $service_account_email,
"aud" => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
"iat" => $now_seconds,
"exp" => $now_seconds+(60*60), // Maximum expiration time is one hour
"uid" => $uid,
"claims" => array(
"premium_account" => $is_premium_account
)
);
return JWT::encode($payload, $private_key, "RS256");
}
با استفاده از ruby-jwt
:
require "jwt"
# Get your service account's email address and private key from the JSON key file
$service_account_email = "service-account@my-project-abc123.iam.gserviceaccount.com"
$private_key = OpenSSL::PKey::RSA.new "-----BEGIN PRIVATE KEY-----\n..."
def create_custom_token(uid, is_premium_account)
now_seconds = Time.now.to_i
payload = {:iss => $service_account_email,
:sub => $service_account_email,
:aud => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
:iat => now_seconds,
:exp => now_seconds+(60*60), # Maximum expiration time is one hour
:uid => uid,
:claims => {:premium_account => is_premium_account}}
JWT.encode payload, $private_key, "RS256"
end
پس از ایجاد توکن سفارشی، آن را به برنامه مشتری خود ارسال کنید تا از آن برای احراز هویت با Firebase استفاده کنید. برای نحوه انجام این کار به نمونه کدهای بالا مراجعه کنید.
عیب یابی
این بخش برخی از مشکلات رایجی که توسعه دهندگان ممکن است در هنگام ایجاد توکن های سفارشی با آن مواجه شوند و نحوه حل آنها را تشریح می کند.
IAM API فعال نیست
اگر شناسه حساب سرویس را برای امضای توکن ها مشخص می کنید، ممکن است با خطای زیر مواجه شوید:
Identity and Access Management (IAM) API has not been used in project 1234567890 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/iam.googleapis.com/overview?project=1234567890 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
Firebase Admin SDK از IAM API برای امضای توکن ها استفاده می کند. این خطا نشان می دهد که IAM API در حال حاضر برای پروژه Firebase شما فعال نیست. پیوند موجود در پیام خطا را در یک مرورگر وب باز کنید و روی دکمه "فعال کردن API" کلیک کنید تا آن را برای پروژه خود فعال کنید.
حساب سرویس مجوزهای لازم را ندارد
اگر حساب سرویس Firebase Admin SDK بدون مجوز iam.serviceAccounts.signBlob
اجرا میشود، ممکن است پیام خطایی مانند زیر دریافت کنید:
Permission iam.serviceAccounts.signBlob is required to perform this operation on service account projects/-/serviceAccounts/{your-service-account-id}.
ساده ترین راه برای حل این مشکل، اعطای نقش IAM «خلق رمز حساب سرویس» به حساب سرویس مورد نظر، معمولاً {project-name}@appspot.gserviceaccount.com
است:
- صفحه IAM و admin را در کنسول Google Cloud باز کنید.
- پروژه خود را انتخاب کنید و روی "ادامه" کلیک کنید.
- روی نماد ویرایش مربوط به حساب سرویسی که می خواهید به روز کنید کلیک کنید.
- روی «افزودن نقش دیگر» کلیک کنید.
- "Service Account Token Creator" را در فیلتر جستجو تایپ کنید و آن را از نتایج انتخاب کنید.
- برای تایید اعطای نقش روی "ذخیره" کلیک کنید.
برای جزئیات بیشتر در مورد این فرآیند به مستندات IAM مراجعه کنید، یا یاد بگیرید که چگونه نقشهای بهروزرسانی را با استفاده از ابزارهای خط فرمان gcloud انجام دهید.
حساب سرویس تعیین نشد
اگر پیام خطایی مشابه زیر دریافت کردید، Firebase Admin SDK به درستی مقداردهی اولیه نشده است.
Failed to determine service account ID. Initialize the SDK with service account credentials or specify a service account ID with iam.serviceAccounts.signBlob permission.
اگر برای کشف خودکار شناسه حساب سرویس به SDK متکی هستید، مطمئن شوید که کد در یک محیط مدیریت شده Google با سرور ابرداده مستقر شده است. در غیر این صورت، حتماً فایل JSON حساب سرویس یا شناسه حساب سرویس را در مقداردهی اولیه SDK مشخص کنید.
، Firebase با اجازه دادن به شما برای احراز هویت کاربران یا دستگاهها با استفاده از JSON Web Tokens (JWT) کنترل کاملی بر احراز هویت به شما میدهد. شما این نشانهها را روی سرور خود تولید میکنید، آنها را به یک دستگاه کلاینت برمیگردانید، و سپس از آنها برای احراز هویت از طریق متد signInWithCustomToken()
استفاده میکنید.
برای دستیابی به این هدف، باید یک نقطه پایانی سرور ایجاد کنید که اعتبار ورود به سیستم را بپذیرد - مانند نام کاربری و رمز عبور - و اگر اعتبارنامه معتبر باشد، یک JWT سفارشی برمیگرداند. سپس JWT سفارشی که از سرور شما بازگردانده میشود، میتواند توسط دستگاه مشتری برای احراز هویت با Firebase ( iOS ، Android ، وب ) استفاده شود. پس از احراز هویت، از این هویت هنگام دسترسی به سایر خدمات Firebase، مانند Firebase Realtime Database و Cloud Storage استفاده میشود. علاوه بر این، محتویات JWT در شی auth
در Realtime Database Security Rules و شی request.auth
در Cloud Storage Security Rules شما در دسترس خواهد بود.
میتوانید با Firebase Admin SDK یک توکن سفارشی ایجاد کنید، یا اگر سرور شما به زبانی نوشته شده است که Firebase به طور بومی پشتیبانی نمیکند، میتوانید از کتابخانه JWT شخص ثالث استفاده کنید.
قبل از شروع
توکنهای سفارشی JWTهای امضا شدهای هستند که کلید خصوصی مورد استفاده برای امضا به یک حساب سرویس Google تعلق دارد. چندین راه برای تعیین حساب سرویس Google که باید توسط Firebase Admin SDK برای امضای توکن های سفارشی استفاده شود، وجود دارد:
- استفاده از فایل JSON حساب سرویس -- این روش را می توان در هر محیطی استفاده کرد، اما از شما می خواهد که فایل JSON حساب سرویس را همراه با کد خود بسته بندی کنید. باید مراقب باشید تا اطمینان حاصل شود که فایل JSON حساب سرویس در معرض اشخاص خارجی قرار نمی گیرد.
- اجازه دادن به Admin SDK برای کشف یک حساب سرویس -- این روش را می توان در محیط های مدیریت شده توسط Google مانند Google Cloud Functions و App Engine استفاده کرد. ممکن است مجبور شوید برخی از مجوزهای اضافی را از طریق کنسول Google Cloud پیکربندی کنید.
- استفاده از شناسه حساب سرویس -- هنگامی که در یک محیط مدیریت شده توسط Google استفاده می شود، این روش با استفاده از کلید حساب سرویس مشخص شده، نشانه ها را امضا می کند. با این حال، از یک سرویس وب راه دور استفاده می کند، و ممکن است مجبور شوید مجوزهای اضافی را برای این حساب سرویس از طریق کنسول Google Cloud پیکربندی کنید.
استفاده از فایل JSON حساب سرویس
فایلهای JSON حساب سرویس حاوی تمام اطلاعات مربوط به حسابهای سرویس (از جمله کلید خصوصی RSA) هستند. آنها را می توان از کنسول Firebase دانلود کرد. دستورالعملهای راهاندازی Admin SDK را برای اطلاعات بیشتر در مورد نحوه راهاندازی اولیه SDK مدیریت با یک فایل JSON حساب سرویس دنبال کنید.
این روش مقداردهی اولیه برای طیف وسیعی از استقرار Admin SDK مناسب است. همچنین Admin SDK را قادر میسازد تا توکنهای سفارشی را به صورت محلی ایجاد و امضا کند، بدون اینکه تماس API از راه دور برقرار کند. اشکال اصلی این روش این است که شما را ملزم می کند یک فایل JSON حساب سرویس را به همراه کد خود بسته بندی کنید. همچنین توجه داشته باشید که کلید خصوصی در فایل JSON حساب سرویس، اطلاعات حساسی است و باید مراقب محرمانه ماندن آن بود. به طور خاص، از افزودن فایلهای JSON حساب سرویس به کنترل نسخه عمومی خودداری کنید.
اجازه دادن به Admin SDK یک حساب سرویس را کشف کند
اگر کد شما در محیطی که توسط Google مدیریت میشود مستقر شده است، Admin SDK میتواند به طور خودکار ابزاری را برای امضای نشانههای سفارشی کشف کند:
اگر کد شما در محیط استاندارد App Engine برای Java، Python یا Go مستقر شده است، Admin SDK میتواند از سرویس App Identity موجود در آن محیط برای امضای توکنهای سفارشی استفاده کند. سرویس App Identity داده ها را با استفاده از حساب سرویسی که توسط Google App Engine برای برنامه شما ارائه شده است امضا می کند.
اگر کد شما در محیط مدیریت شده دیگری (به عنوان مثال Google Cloud Functions، Google Compute Engine) مستقر شده باشد، Firebase Admin SDK می تواند به طور خودکار یک رشته شناسه حساب سرویس را از سرور ابرداده محلی پیدا کند. سپس شناسه حساب سرویس کشف شده همراه با سرویس IAM برای امضای توکن ها از راه دور استفاده می شود.
برای استفاده از این روشهای امضا، SDK را با اطلاعات کاربری پیشفرض Google Application مقداردهی اولیه کنید و رشته ID حساب سرویس را مشخص نکنید:
initializeApp();
FirebaseApp.initializeApp();
default_app = firebase_admin.initialize_app()
app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
log.Fatalf("error initializing app: %v\n", err)
}
FirebaseApp.Create();
برای آزمایش همان کد به صورت محلی، یک فایل JSON حساب سرویس را دانلود کنید و متغیر محیطی GOOGLE_APPLICATION_CREDENTIALS
را تنظیم کنید تا به آن اشاره کند.
اگر Firebase Admin SDK باید رشته ID حساب سرویس را پیدا کند، زمانی که کد شما برای اولین بار یک توکن سفارشی ایجاد میکند، این کار را انجام میدهد. نتیجه ذخیره میشود و برای عملیات امضای نشانههای بعدی مجدداً استفاده میشود. شناسه حساب سرویس کشف شده خودکار معمولاً یکی از حسابهای خدمات پیشفرض ارائه شده توسط Google Cloud است:
درست مانند شناسههای حساب سرویس که بهصراحت مشخص شدهاند، شناسههای حساب سرویس با کشف خودکار باید مجوز iam.serviceAccounts.signBlob
را داشته باشند تا ایجاد توکن سفارشی کار کند. برای اعطای مجوزهای لازم به حسابهای سرویس پیشفرض، ممکن است مجبور شوید از IAM و بخش سرپرست کنسول Google Cloud استفاده کنید. برای جزئیات بیشتر به بخش عیب یابی زیر مراجعه کنید.
با استفاده از شناسه حساب سرویس
برای حفظ سازگاری بین بخشهای مختلف برنامهتان، میتوانید شناسه حساب سرویسی را مشخص کنید که کلیدهای آن برای امضای نشانهها هنگام اجرا در یک محیط تحت مدیریت Google مورد استفاده قرار میگیرد. این میتواند خطمشیهای IAM را سادهتر و ایمنتر کند و از گنجاندن فایل JSON حساب سرویس در کد خود اجتناب کند.
شناسه حساب سرویس را می توان در کنسول Google Cloud یا در قسمت client_email
یک فایل JSON حساب سرویس دانلود شده پیدا کرد. شناسههای حساب سرویس، آدرسهای ایمیلی هستند که قالب زیر را دارند: <client-id>@<project-id>.iam.gserviceaccount.com
. آنها حسابهای سرویس را در پروژههای Firebase و Google Cloud بهطور منحصربهفرد شناسایی میکنند.
برای ایجاد توکن های سفارشی با استفاده از شناسه حساب سرویس جداگانه، SDK را مطابق شکل زیر مقداردهی اولیه کنید:
initializeApp({
serviceAccountId: 'my-client-id@my-project-id.iam.gserviceaccount.com',
});
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(GoogleCredentials.getApplicationDefault())
.setServiceAccountId("my-client-id@my-project-id.iam.gserviceaccount.com")
.build();
FirebaseApp.initializeApp(options);
options = {
'serviceAccountId': 'my-client-id@my-project-id.iam.gserviceaccount.com',
}
firebase_admin.initialize_app(options=options)
conf := &firebase.Config{
ServiceAccountID: "my-client-id@my-project-id.iam.gserviceaccount.com",
}
app, err := firebase.NewApp(context.Background(), conf)
if err != nil {
log.Fatalf("error initializing app: %v\n", err)
}
FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.GetApplicationDefault(),
ServiceAccountId = "my-client-id@my-project-id.iam.gserviceaccount.com",
});
شناسههای حساب سرویس اطلاعات حساسی نیستند و بنابراین قرار گرفتن در معرض آنها بیاهمیت است. با این حال، برای امضای توکنهای سفارشی با حساب سرویس مشخصشده، Firebase Admin SDK باید یک سرویس راه دور را فراخوانی کند. علاوه بر این، باید مطمئن شوید که حساب سرویس Admin SDK که برای برقراری این تماس از آن استفاده میکند - معمولاً {project-name}@appspot.gserviceaccount.com
- دارای مجوز iam.serviceAccounts.signBlob
است. برای جزئیات بیشتر به بخش عیب یابی زیر مراجعه کنید.
با استفاده از Firebase Admin SDK توکن های سفارشی ایجاد کنید
Firebase Admin SDK دارای یک روش داخلی برای ایجاد توکن های سفارشی است. حداقل باید یک uid
ارائه کنید که می تواند هر رشته ای باشد اما باید کاربر یا دستگاهی را که احراز هویت می کنید مشخص کند. این توکن ها پس از یک ساعت منقضی می شوند.
const uid = 'some-uid';
getAuth()
.createCustomToken(uid)
.then((customToken) => {
// Send token back to client
})
.catch((error) => {
console.log('Error creating custom token:', error);
});
String uid = "some-uid";
String customToken = FirebaseAuth.getInstance().createCustomToken(uid);
// Send token back to client
uid = 'some-uid'
custom_token = auth.create_custom_token(uid)
client, err := app.Auth(context.Background())
if err != nil {
log.Fatalf("error getting Auth client: %v\n", err)
}
token, err := client.CustomToken(ctx, "some-uid")
if err != nil {
log.Fatalf("error minting custom token: %v\n", err)
}
log.Printf("Got custom token: %v\n", token)
var uid = "some-uid";
string customToken = await FirebaseAuth.DefaultInstance.CreateCustomTokenAsync(uid);
// Send token back to client
همچنین می توانید به صورت اختیاری ادعاهای اضافی را برای گنجاندن در توکن سفارشی مشخص کنید. به عنوان مثال، در زیر، یک فیلد premiumAccount
به توکن سفارشی اضافه شده است که در اشیاء auth
/ request.auth
در قوانین امنیتی شما در دسترس خواهد بود:
const userId = 'some-uid';
const additionalClaims = {
premiumAccount: true,
};
getAuth()
.createCustomToken(userId, additionalClaims)
.then((customToken) => {
// Send token back to client
})
.catch((error) => {
console.log('Error creating custom token:', error);
});
String uid = "some-uid";
Map<String, Object> additionalClaims = new HashMap<String, Object>();
additionalClaims.put("premiumAccount", true);
String customToken = FirebaseAuth.getInstance()
.createCustomToken(uid, additionalClaims);
// Send token back to client
uid = 'some-uid'
additional_claims = {
'premiumAccount': True
}
custom_token = auth.create_custom_token(uid, additional_claims)
client, err := app.Auth(context.Background())
if err != nil {
log.Fatalf("error getting Auth client: %v\n", err)
}
claims := map[string]interface{}{
"premiumAccount": true,
}
token, err := client.CustomTokenWithClaims(ctx, "some-uid", claims)
if err != nil {
log.Fatalf("error minting custom token: %v\n", err)
}
log.Printf("Got custom token: %v\n", token)
var uid = "some-uid";
var additionalClaims = new Dictionary<string, object>()
{
{ "premiumAccount", true },
};
string customToken = await FirebaseAuth.DefaultInstance
.CreateCustomTokenAsync(uid, additionalClaims);
// Send token back to client
نامهای رمز سفارشی رزرو شده
با استفاده از توکن های سفارشی روی مشتریان وارد شوید
پس از ایجاد یک توکن سفارشی، باید آن را به برنامه مشتری خود ارسال کنید. برنامه مشتری با فراخوانی signInWithCustomToken()
با توکن سفارشی احراز هویت میشود:
هدف-C
[[FIRAuth auth] signInWithCustomToken:customToken
completion:^(FIRAuthDataResult * _Nullable authResult,
NSError * _Nullable error) {
// ...
}];
سویفت
Auth.auth().signIn(withCustomToken: customToken ?? "") { user, error in
// ...
}
mAuth.signInWithCustomToken(mCustomToken)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCustomToken:success");
FirebaseUser user = mAuth.getCurrentUser();
updateUI(user);
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCustomToken:failure", task.getException());
Toast.makeText(CustomAuthActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
updateUI(null);
}
}
});
auth.SignInWithCustomTokenAsync(custom_token).ContinueWith(task => {
if (task.IsCanceled) {
Debug.LogError("SignInWithCustomTokenAsync was canceled.");
return;
}
if (task.IsFaulted) {
Debug.LogError("SignInWithCustomTokenAsync encountered an error: " + task.Exception);
return;
}
Firebase.Auth.AuthResult result = task.Result;
Debug.LogFormat("User signed in successfully: {0} ({1})",
result.User.DisplayName, result.User.UserId);
});
firebase::Future<firebase::auth::AuthResult> result =
auth->SignInWithCustomToken(custom_token);
firebase.auth().signInWithCustomToken(token)
.then((userCredential) => {
// Signed in
var user = userCredential.user;
// ...
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
import { getAuth, signInWithCustomToken } from "firebase/auth";
const auth = getAuth();
signInWithCustomToken(auth, token)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
// ...
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
// ...
});
اگر احراز هویت با موفقیت انجام شود، کاربر شما اکنون با حساب مشخص شده توسط uid
موجود در کد سفارشی وارد برنامه مشتری شما خواهد شد. اگر آن حساب قبلا وجود نداشت، یک رکورد برای آن کاربر ایجاد می شود.
مانند سایر روشهای ورود به سیستم (مانند signInWithEmailAndPassword()
و signInWithCredential()
) شی auth
در Realtime Database Security Rules و شی request.auth
در Cloud Storage Security Rules شما با uid
کاربر پر میشود. در این حالت، uid
همانی خواهد بود که هنگام تولید توکن سفارشی مشخص کردهاید.
{
"rules": {
"adminContent": {
".read": "auth.uid === 'some-uid'"
}
}
}
service firebase.storage {
match /b/<your-firebase-storage-bucket>/o {
match /adminContent/{filename} {
allow read, write: if request.auth != null && request.auth.uid == "some-uid";
}
}
}
اگر توکن سفارشی حاوی ادعاهای اضافی باشد، میتوان آنها را از auth.token
( Firebase Realtime Database ) یا شی request.auth.token
( Cloud Storage ) در قوانین شما ارجاع داد:
{
"rules": {
"premiumContent": {
".read": "auth.token.premiumAccount === true"
}
}
}
service firebase.storage {
match /b/<your-firebase-storage-bucket>/o {
match /premiumContent/{filename} {
allow read, write: if request.auth.token.premiumAccount == true;
}
}
}
با استفاده از یک کتابخانه JWT شخص ثالث، توکن های سفارشی ایجاد کنید
اگر باطن شما به زبانی است که Firebase Admin SDK رسمی ندارد، همچنان می توانید به صورت دستی توکن های سفارشی ایجاد کنید. ابتدا یک کتابخانه JWT شخص ثالث برای زبان خود پیدا کنید . سپس، از آن کتابخانه JWT برای ایجاد یک JWT که شامل ادعاهای زیر است استفاده کنید:
ادعاهای توکن سفارشی | ||
---|---|---|
alg | الگوریتم | "RS256" |
iss | صادر کننده | آدرس ایمیل حساب سرویس پروژه شما |
sub | موضوع | آدرس ایمیل حساب سرویس پروژه شما |
aud | مخاطب | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat | صادر شده در زمان | زمان فعلی، در ثانیه از دوران یونیکس |
exp | زمان انقضا | زمان، بر حسب ثانیه از دوره یونیکس، که در آن توکن منقضی میشود. می تواند حداکثر 3600 ثانیه دیرتر از iat باشد.توجه: این فقط زمانی را کنترل می کند که خود توکن سفارشی منقضی شود. اما هنگامی که کاربر را در استفاده از signInWithCustomToken() امضا کردید ، آنها تا زمانی که جلسه آنها باطل نشود یا کاربر امضا شود ، وارد دستگاه می شوند. |
uid | شناسه منحصر به فرد کاربر امضا شده باید یک رشته باشد ، بین 1 تا 128 کاراکتر طولانی ، فراگیر. uid کوتاهتر عملکرد بهتری ارائه می دهد. | |
claims (اختیاری) | ادعاهای سفارشی اختیاری که در قوانین امنیتی auth / request.auth گنجانده شود |
در اینجا چند نمونه از نحوه ایجاد نشانه های سفارشی به زبانهای مختلف وجود دارد که Admin SDK Firebase پشتیبانی نمی کند:
با استفاده از php-jwt
:
// Requires: composer require firebase/php-jwt
use Firebase\JWT\JWT;
// Get your service account's email address and private key from the JSON key file
$service_account_email = "abc-123@a-b-c-123.iam.gserviceaccount.com";
$private_key = "-----BEGIN PRIVATE KEY-----...";
function create_custom_token($uid, $is_premium_account) {
global $service_account_email, $private_key;
$now_seconds = time();
$payload = array(
"iss" => $service_account_email,
"sub" => $service_account_email,
"aud" => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
"iat" => $now_seconds,
"exp" => $now_seconds+(60*60), // Maximum expiration time is one hour
"uid" => $uid,
"claims" => array(
"premium_account" => $is_premium_account
)
);
return JWT::encode($payload, $private_key, "RS256");
}
با استفاده از ruby-jwt
:
require "jwt"
# Get your service account's email address and private key from the JSON key file
$service_account_email = "service-account@my-project-abc123.iam.gserviceaccount.com"
$private_key = OpenSSL::PKey::RSA.new "-----BEGIN PRIVATE KEY-----\n..."
def create_custom_token(uid, is_premium_account)
now_seconds = Time.now.to_i
payload = {:iss => $service_account_email,
:sub => $service_account_email,
:aud => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
:iat => now_seconds,
:exp => now_seconds+(60*60), # Maximum expiration time is one hour
:uid => uid,
:claims => {:premium_account => is_premium_account}}
JWT.encode payload, $private_key, "RS256"
end
پس از ایجاد توکن سفارشی ، آن را به برنامه مشتری خود ارسال کنید تا برای تأیید اعتبار با Firebase استفاده کنید. برای نحوه انجام این کار نمونه های کد بالا را مشاهده کنید.
عیب یابی
در این بخش برخی از مشکلات متداول که توسعه دهندگان ممکن است هنگام ایجاد نشانه های سفارشی و نحوه حل آنها با آنها روبرو شوند.
IAM API فعال نشده است
اگر در حال مشخص کردن شناسه حساب خدمات برای امضای نشانه ها هستید ، ممکن است خطایی مشابه موارد زیر داشته باشید:
Identity and Access Management (IAM) API has not been used in project 1234567890 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/iam.googleapis.com/overview?project=1234567890 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
Admin SDK Admin Firebase از API IAM برای امضای نشانه ها استفاده می کند. این خطا نشان می دهد که API IAM در حال حاضر برای پروژه Firebase شما فعال نشده است. پیوند را در پیام خطا در یک مرورگر وب باز کنید و بر روی دکمه "Enable API" کلیک کنید تا آن را برای پروژه خود فعال کنید.
حساب خدمات مجوزهای لازم را ندارد
اگر حساب خدمات SDK Admin Firebase Admin در حال اجرا باشد همانطور که iam.serviceAccounts.signBlob
را ندارد ، ممکن است یک پیام خطا مانند موارد زیر دریافت کنید:
Permission iam.serviceAccounts.signBlob is required to perform this operation on service account projects/-/serviceAccounts/{your-service-account-id}.
ساده ترین راه برای حل و فصل این امر ، اعطای نقش "سازنده حساب کاربری خدمات" IAM به حساب خدمات مورد نظر ، معمولاً {project-name}@appspot.gserviceaccount.com
:
- صفحه IAM و Admin را در کنسول Google Cloud باز کنید.
- پروژه خود را انتخاب کرده و روی "ادامه" کلیک کنید.
- روی نماد ویرایش مربوط به حساب خدمات مورد نظر برای به روزرسانی کلیک کنید.
- روی "اضافه کردن نقش دیگر" کلیک کنید.
- "سازنده توکن حساب کاربری سرویس" را در فیلتر جستجو تایپ کرده و از نتایج آن را انتخاب کنید.
- برای تأیید کمک هزینه نقش ، روی "ذخیره" کلیک کنید.
برای اطلاعات بیشتر در مورد این فرآیند به اسناد IAM مراجعه کنید ، یا یاد بگیرید که چگونه نقش ها را با استفاده از ابزارهای خط فرمان GCLOUD انجام دهید.
تعیین حساب خدمات انجام نشد
اگر پیام خطایی مشابه موارد زیر دریافت کنید ، SDK Admin Firebase به درستی اولیه نشده است.
Failed to determine service account ID. Initialize the SDK with service account credentials or specify a service account ID with iam.serviceAccounts.signBlob permission.
اگر برای کشف خودکار شناسه حساب خدمات به SDK تکیه می کنید ، مطمئن شوید که این کد در یک محیط Google مدیریت شده با یک سرور ابرداده مستقر شده است. در غیر این صورت ، حتماً در اولیه سازی SDK ، پرونده حساب JSON یا شناسه حساب خدمات را مشخص کنید.
، Firebase با اجازه دادن به تأیید اعتبار کاربران یا دستگاه ها با استفاده از نشانه های Secure JSON Web (JWTS) ، کنترل کاملی بر تأیید اعتبار به شما می دهد. شما این نشانهها را روی سرور خود تولید میکنید، آنها را به یک دستگاه کلاینت برمیگردانید، و سپس از آنها برای احراز هویت از طریق متد signInWithCustomToken()
استفاده میکنید.
برای دستیابی به این هدف ، شما باید یک نقطه پایانی سرور ایجاد کنید که اعتبار ورود به سیستم را بپذیرد-مانند نام کاربری و رمز عبور-و اگر اعتبار معتبر باشد ، JWT سفارشی را برمی گرداند. JWT سفارشی که از سرور شما برگشته است می تواند توسط یک دستگاه مشتری برای تأیید اعتبار با Firebase ( iOS+ ، Android ، Web ) استفاده شود. پس از تأیید اعتبار ، این هویت هنگام دسترسی به سایر خدمات Firebase ، مانند Firebase Realtime Database و Cloud Storage استفاده می شود. علاوه بر این ، محتوای JWT در Realtime Database Security Rules شما و request.auth
مورد Outh.auth در Cloud Storage Security Rules شما در شیء auth
در دسترس خواهد بود.
اگر سرور شما به زبانی نوشته شده است که Firebase از آن پشتیبانی نمی کند ، می توانید یک نشانه سفارشی با Admin SDK Firebase ایجاد کنید ، یا می توانید از یک کتابخانه JWT شخص ثالث استفاده کنید که Firebase از آن پشتیبانی نمی کند.
قبل از شروع
توکن های سفارشی JWT ها را امضا می کنند که کلید خصوصی مورد استفاده برای امضای متعلق به یک حساب خدمات Google است. روش های مختلفی برای مشخص کردن حساب Service Google وجود دارد که باید توسط Firebase Admin SDK برای امضای نشانه های سفارشی استفاده شود:
- با استفاده از یک فایل JSON حساب کاربری - این روش می تواند در هر محیطی استفاده شود ، اما شما را ملزم به بسته بندی یک فایل حساب JSON حساب کاربری به همراه کد خود می کند. باید مراقبت ویژه ای انجام شود تا اطمینان حاصل شود که پرونده JSON حساب خدمات در معرض احزاب خارجی قرار نگرفته است.
- اجازه دهید مدیر SDK یک حساب کاربری سرویس را کشف کند - این روش می تواند در محیط هایی که توسط Google مانند عملکردهای Google Cloud و App Engine اداره می شود ، استفاده شود. ممکن است مجبور شوید برخی از مجوزهای اضافی را از طریق کنسول Google Cloud پیکربندی کنید.
- با استفاده از یک شناسه حساب کاربری سرویس -هنگامی که در یک محیط با مدیریت گوگل استفاده می شود ، این روش با استفاده از کلید حساب خدمات مشخص شده ، نشانه ها را امضا می کند. با این حال ، از یک سرویس وب از راه دور استفاده می کند ، و ممکن است شما مجبور شوید مجوزهای اضافی را برای این حساب سرویس از طریق کنسول Google Cloud پیکربندی کنید.
با استفاده از یک پرونده JSON حساب کاربری
پرونده های حساب خدمات JSON شامل کلیه اطلاعات مربوط به حساب های خدمات (از جمله کلید خصوصی RSA) است. آنها را می توان از کنسول Firebase بارگیری کرد. برای اطلاعات بیشتر در مورد نحوه اولیه سازی مدیر SDK با یک پرونده JSON حساب سرویس ، دستورالعمل های تنظیم شده SDK را دنبال کنید.
این روش اولیه سازی برای طیف گسترده ای از استقرار SDK Admin مناسب است. همچنین Admin SDK را قادر می سازد تا بدون برقراری تماس API از راه دور ، نشانه های سفارشی را به صورت محلی ایجاد و امضا کند. اشکال اصلی این رویکرد این است که شما را ملزم به بسته بندی یک فایل حساب خدمات JSON به همراه کد خود می کند. همچنین توجه داشته باشید که کلید خصوصی در یک پرونده JSON حساب خدمات اطلاعات حساس است و برای محرمانه نگه داشتن آن باید مراقبت ویژه ای انجام شود. به طور خاص ، از اضافه کردن پرونده های حساب کاربری JSON به کنترل نسخه عمومی خودداری کنید.
اجازه دهید مدیر SDK یک حساب کاربری خدمات را کشف کند
اگر کد شما در محیطی که توسط Google اداره می شود ، مستقر شده است ، Admin SDK می تواند سعی در کشف خودکار وسیله ای برای امضای نشانه های سفارشی داشته باشد:
اگر کد شما در محیط استاندارد App Engine برای جاوا ، پایتون یا GO مستقر شده باشد ، Admin SDK می تواند از سرویس هویت برنامه موجود در آن محیط برای امضای نشانه های سفارشی استفاده کند. سرویس هویت برنامه داده ها را با استفاده از یک حساب خدمات ارائه شده برای برنامه شما توسط Google App Engine امضا می کند.
اگر کد شما در برخی از محیط های مدیریت شده دیگر مستقر شده باشد (به عنوان مثال عملکردهای Google Cloud ، Google Compute Engine) ، Firebase Admin SDK می تواند یک رشته شناسه حساب خدمات را از سرور ابرداده محلی کشف کند. سپس شناسه حساب خدمات کشف شده در رابطه با سرویس IAM برای امضای نشانه ها از راه دور استفاده می شود.
برای استفاده از این روشهای امضای ، SDK را با اعتبار پیش فرض برنامه Google آغاز کنید و رشته شناسه حساب سرویس را مشخص نکنید:
initializeApp();
FirebaseApp.initializeApp();
default_app = firebase_admin.initialize_app()
app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
log.Fatalf("error initializing app: %v\n", err)
}
FirebaseApp.Create();
برای آزمایش همان کد به صورت محلی ، یک فایل JSON حساب کاربری سرویس را بارگیری کرده و متغیر محیط GOOGLE_APPLICATION_CREDENTIALS
را تنظیم کنید تا به آن اشاره کنید.
اگر SDK Admin Firebase مجبور است رشته شناسه حساب خدمات را کشف کند ، وقتی کد شما برای اولین بار یک نشانه سفارشی ایجاد می کند ، این کار را انجام می دهد. نتیجه برای عملیات امضاء بعدی ذخیره شده و مورد استفاده مجدد قرار می گیرد. شناسه حساب خدمات کشف شده خودکار معمولاً یکی از حسابهای خدمات پیش فرض ارائه شده توسط Google Cloud است:
درست مانند شناسه های حساب خدمات صریح و مشخص ، شناسه های حساب خدمات کشف خودکار باید دارای مجوز iam.serviceAccounts.signBlob
برای ایجاد توکن سفارشی باشند. ممکن است شما مجبور شوید از بخش IAM و مدیر کنسول Google Cloud استفاده کنید تا مجوزهای لازم را به حساب های خدمات پیش فرض اعطا کنید. برای اطلاعات بیشتر به بخش عیب یابی در زیر مراجعه کنید.
با استفاده از شناسه حساب خدمات
برای حفظ سازگاری بین قسمت های مختلف برنامه خود ، می توانید یک شناسه حساب خدمات را مشخص کنید که از کلیدهای آن برای امضای نشانه ها هنگام اجرای در یک محیط با مدیریت گوگل استفاده می شود. این می تواند خط مشی های IAM ساده تر و ایمن تر شود و از نیاز به درج پرونده JSON حساب خدمات در کد شما جلوگیری شود.
شناسه حساب سرویس را می توانید در کنسول Google Cloud یا در قسمت client_email
یک پرونده JSON حساب سرویس بارگیری شده پیدا کنید. شناسه های حساب خدمات آدرس های ایمیل هستند که دارای فرمت زیر هستند: <client-id>@<project-id>.iam.gserviceaccount.com
. آنها به طور منحصر به فرد حساب های خدمات را در پروژه های Firebase و Google Cloud شناسایی می کنند.
برای ایجاد نشانه های سفارشی با استفاده از یک شناسه حساب خدمات جداگانه ، SDK را مطابق شکل زیر آغاز کنید:
initializeApp({
serviceAccountId: 'my-client-id@my-project-id.iam.gserviceaccount.com',
});
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(GoogleCredentials.getApplicationDefault())
.setServiceAccountId("my-client-id@my-project-id.iam.gserviceaccount.com")
.build();
FirebaseApp.initializeApp(options);
options = {
'serviceAccountId': 'my-client-id@my-project-id.iam.gserviceaccount.com',
}
firebase_admin.initialize_app(options=options)
conf := &firebase.Config{
ServiceAccountID: "my-client-id@my-project-id.iam.gserviceaccount.com",
}
app, err := firebase.NewApp(context.Background(), conf)
if err != nil {
log.Fatalf("error initializing app: %v\n", err)
}
FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.GetApplicationDefault(),
ServiceAccountId = "my-client-id@my-project-id.iam.gserviceaccount.com",
});
شناسه حساب خدمات اطلاعات حساس نیست و بنابراین قرار گرفتن در معرض آنها بی نتیجه است. با این حال ، برای امضای نشانه های سفارشی با حساب خدمات مشخص شده ، SDK Admin Firebase باید از یک سرویس از راه دور استفاده کند. علاوه بر این ، شما همچنین باید اطمینان حاصل کنید که حساب سرویس Admin SDK برای برقراری این تماس-به طور معمول {project-name}@appspot.gserviceaccount.com
دارای مجوز iam.serviceAccounts.signBlob
است. برای اطلاعات بیشتر به بخش عیب یابی در زیر مراجعه کنید.
با استفاده از SDK Admin Firebase نشانه های سفارشی ایجاد کنید
Firebase Admin SDK یک روش داخلی برای ایجاد نشانه های سفارشی دارد. حداقل ، شما باید یک uid
تهیه کنید ، که می تواند هر رشته ای باشد اما باید به طور منحصر به فرد کاربر یا دستگاه مورد نظر خود را شناسایی کنید. این توکن ها پس از یک ساعت منقضی می شوند.
const uid = 'some-uid';
getAuth()
.createCustomToken(uid)
.then((customToken) => {
// Send token back to client
})
.catch((error) => {
console.log('Error creating custom token:', error);
});
String uid = "some-uid";
String customToken = FirebaseAuth.getInstance().createCustomToken(uid);
// Send token back to client
uid = 'some-uid'
custom_token = auth.create_custom_token(uid)
client, err := app.Auth(context.Background())
if err != nil {
log.Fatalf("error getting Auth client: %v\n", err)
}
token, err := client.CustomToken(ctx, "some-uid")
if err != nil {
log.Fatalf("error minting custom token: %v\n", err)
}
log.Printf("Got custom token: %v\n", token)
var uid = "some-uid";
string customToken = await FirebaseAuth.DefaultInstance.CreateCustomTokenAsync(uid);
// Send token back to client
همچنین می توانید به صورت اختیاری ادعاهای اضافی را که در توکن سفارشی گنجانده شده است مشخص کنید. به عنوان مثال ، در زیر ، یک قسمت premiumAccount
به Token Custom اضافه شده است ، که در auth
/ request.auth
در قوانین امنیتی شما موجود خواهد بود:
const userId = 'some-uid';
const additionalClaims = {
premiumAccount: true,
};
getAuth()
.createCustomToken(userId, additionalClaims)
.then((customToken) => {
// Send token back to client
})
.catch((error) => {
console.log('Error creating custom token:', error);
});
String uid = "some-uid";
Map<String, Object> additionalClaims = new HashMap<String, Object>();
additionalClaims.put("premiumAccount", true);
String customToken = FirebaseAuth.getInstance()
.createCustomToken(uid, additionalClaims);
// Send token back to client
uid = 'some-uid'
additional_claims = {
'premiumAccount': True
}
custom_token = auth.create_custom_token(uid, additional_claims)
client, err := app.Auth(context.Background())
if err != nil {
log.Fatalf("error getting Auth client: %v\n", err)
}
claims := map[string]interface{}{
"premiumAccount": true,
}
token, err := client.CustomTokenWithClaims(ctx, "some-uid", claims)
if err != nil {
log.Fatalf("error minting custom token: %v\n", err)
}
log.Printf("Got custom token: %v\n", token)
var uid = "some-uid";
var additionalClaims = new Dictionary<string, object>()
{
{ "premiumAccount", true },
};
string customToken = await FirebaseAuth.DefaultInstance
.CreateCustomTokenAsync(uid, additionalClaims);
// Send token back to client
نام های توکن سفارشی رزرو شده
با استفاده از نشانه های سفارشی روی مشتری ها وارد شوید
پس از ایجاد یک نشانه سفارشی ، باید آن را به برنامه مشتری خود ارسال کنید. برنامه مشتری با تماس با signInWithCustomToken()
با نشانه سفارشی تأیید می شود:
هدف-C
[[FIRAuth auth] signInWithCustomToken:customToken
completion:^(FIRAuthDataResult * _Nullable authResult,
NSError * _Nullable error) {
// ...
}];
سویفت
Auth.auth().signIn(withCustomToken: customToken ?? "") { user, error in
// ...
}
mAuth.signInWithCustomToken(mCustomToken)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCustomToken:success");
FirebaseUser user = mAuth.getCurrentUser();
updateUI(user);
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCustomToken:failure", task.getException());
Toast.makeText(CustomAuthActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
updateUI(null);
}
}
});
auth.SignInWithCustomTokenAsync(custom_token).ContinueWith(task => {
if (task.IsCanceled) {
Debug.LogError("SignInWithCustomTokenAsync was canceled.");
return;
}
if (task.IsFaulted) {
Debug.LogError("SignInWithCustomTokenAsync encountered an error: " + task.Exception);
return;
}
Firebase.Auth.AuthResult result = task.Result;
Debug.LogFormat("User signed in successfully: {0} ({1})",
result.User.DisplayName, result.User.UserId);
});
firebase::Future<firebase::auth::AuthResult> result =
auth->SignInWithCustomToken(custom_token);
firebase.auth().signInWithCustomToken(token)
.then((userCredential) => {
// Signed in
var user = userCredential.user;
// ...
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
import { getAuth, signInWithCustomToken } from "firebase/auth";
const auth = getAuth();
signInWithCustomToken(auth, token)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
// ...
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
// ...
});
اگر تأیید اعتبار موفق شود ، کاربر شما اکنون با حساب مشخص شده توسط uid
موجود در توکن سفارشی وارد برنامه مشتری شما می شود. اگر قبلاً آن حساب وجود نداشته باشد ، رکوردی برای آن کاربر ایجاد می شود.
به همان روشی که با سایر روشهای ورود به سیستم (مانند signInWithEmailAndPassword()
و signInWithCredential()
uid
شیء auth
در قوانین امنیتی Cloud Storage Security Rules Realtime Database Security Rules شما و request.auth
. در این حالت ، uid
یکی از مواردی است که شما هنگام تولید نشانه سفارشی مشخص کرده اید.
{
"rules": {
"adminContent": {
".read": "auth.uid === 'some-uid'"
}
}
}
service firebase.storage {
match /b/<your-firebase-storage-bucket>/o {
match /adminContent/{filename} {
allow read, write: if request.auth != null && request.auth.uid == "some-uid";
}
}
}
اگر نشانه سفارشی حاوی ادعاهای اضافی Cloud Storage ، می توان آنها را از auth.token
( Firebase Realtime Database ) یا request.auth.token
استفاده کرد.
{
"rules": {
"premiumContent": {
".read": "auth.token.premiumAccount === true"
}
}
}
service firebase.storage {
match /b/<your-firebase-storage-bucket>/o {
match /premiumContent/{filename} {
allow read, write: if request.auth.token.premiumAccount == true;
}
}
}
با استفاده از یک کتابخانه JWT شخص ثالث ، نشانه های سفارشی ایجاد کنید
اگر باطن شما به زبانی است که یک مدیر رسمی SDK برای Firebase SDK ندارد ، هنوز هم می توانید به صورت دستی نشانه های سفارشی ایجاد کنید. اول ، یک کتابخانه JWT شخص ثالث را برای زبان خود پیدا کنید . سپس از آن کتابخانه JWT برای نعناع JWT استفاده کنید که شامل ادعاهای زیر است:
ادعاهای توکن سفارشی | ||
---|---|---|
alg | الگوریتم | "RS256" |
iss | صادر کننده | آدرس ایمیل حساب خدمات پروژه شما |
sub | موضوع | آدرس ایمیل حساب خدمات پروژه شما |
aud | مخاطب | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat | زمان صادر شده | زمان فعلی ، در چند ثانیه از دوره یونیکس |
exp | زمان انقضا | زمان ، در چند ثانیه از دوره یونیکس ، که در آن نشانه منقضی می شود. این می تواند حداکثر 3600 ثانیه دیرتر از iat باشد.توجه: این تنها زمان انقضاء توکین سفارشی را کنترل می کند. اما هنگامی که کاربر را در استفاده از signInWithCustomToken() امضا کردید ، آنها تا زمانی که جلسه آنها باطل نشود یا کاربر امضا شود ، وارد دستگاه می شوند. |
uid | شناسه منحصر به فرد کاربر امضا شده باید یک رشته باشد ، بین 1 تا 128 کاراکتر طولانی ، فراگیر. uid کوتاهتر عملکرد بهتری ارائه می دهد. | |
claims (اختیاری) | ادعاهای سفارشی اختیاری که در قوانین امنیتی auth / request.auth گنجانده شود |
در اینجا چند نمونه از نحوه ایجاد نشانه های سفارشی به زبانهای مختلف وجود دارد که Admin SDK Firebase پشتیبانی نمی کند:
با استفاده از php-jwt
:
// Requires: composer require firebase/php-jwt
use Firebase\JWT\JWT;
// Get your service account's email address and private key from the JSON key file
$service_account_email = "abc-123@a-b-c-123.iam.gserviceaccount.com";
$private_key = "-----BEGIN PRIVATE KEY-----...";
function create_custom_token($uid, $is_premium_account) {
global $service_account_email, $private_key;
$now_seconds = time();
$payload = array(
"iss" => $service_account_email,
"sub" => $service_account_email,
"aud" => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
"iat" => $now_seconds,
"exp" => $now_seconds+(60*60), // Maximum expiration time is one hour
"uid" => $uid,
"claims" => array(
"premium_account" => $is_premium_account
)
);
return JWT::encode($payload, $private_key, "RS256");
}
با استفاده از ruby-jwt
:
require "jwt"
# Get your service account's email address and private key from the JSON key file
$service_account_email = "service-account@my-project-abc123.iam.gserviceaccount.com"
$private_key = OpenSSL::PKey::RSA.new "-----BEGIN PRIVATE KEY-----\n..."
def create_custom_token(uid, is_premium_account)
now_seconds = Time.now.to_i
payload = {:iss => $service_account_email,
:sub => $service_account_email,
:aud => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
:iat => now_seconds,
:exp => now_seconds+(60*60), # Maximum expiration time is one hour
:uid => uid,
:claims => {:premium_account => is_premium_account}}
JWT.encode payload, $private_key, "RS256"
end
پس از ایجاد توکن سفارشی ، آن را به برنامه مشتری خود ارسال کنید تا برای تأیید اعتبار با Firebase استفاده کنید. برای نحوه انجام این کار نمونه های کد بالا را مشاهده کنید.
عیب یابی
در این بخش برخی از مشکلات متداول که توسعه دهندگان ممکن است هنگام ایجاد نشانه های سفارشی و نحوه حل آنها با آنها روبرو شوند.
IAM API فعال نشده است
اگر در حال مشخص کردن شناسه حساب خدمات برای امضای نشانه ها هستید ، ممکن است خطایی مشابه موارد زیر داشته باشید:
Identity and Access Management (IAM) API has not been used in project 1234567890 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/iam.googleapis.com/overview?project=1234567890 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
Admin SDK Admin Firebase از API IAM برای امضای نشانه ها استفاده می کند. این خطا نشان می دهد که API IAM در حال حاضر برای پروژه Firebase شما فعال نشده است. پیوند را در پیام خطا در یک مرورگر وب باز کنید و بر روی دکمه "Enable API" کلیک کنید تا آن را برای پروژه خود فعال کنید.
حساب خدمات مجوزهای لازم را ندارد
اگر حساب خدمات SDK Admin Firebase Admin در حال اجرا باشد همانطور که iam.serviceAccounts.signBlob
را ندارد ، ممکن است یک پیام خطا مانند موارد زیر دریافت کنید:
Permission iam.serviceAccounts.signBlob is required to perform this operation on service account projects/-/serviceAccounts/{your-service-account-id}.
ساده ترین راه برای حل و فصل این امر ، اعطای نقش "سازنده حساب کاربری خدمات" IAM به حساب خدمات مورد نظر ، معمولاً {project-name}@appspot.gserviceaccount.com
:
- صفحه IAM و Admin را در کنسول Google Cloud باز کنید.
- پروژه خود را انتخاب کرده و روی "ادامه" کلیک کنید.
- روی نماد ویرایش مربوط به حساب خدمات مورد نظر برای به روزرسانی کلیک کنید.
- روی "اضافه کردن نقش دیگر" کلیک کنید.
- "سازنده توکن حساب کاربری سرویس" را در فیلتر جستجو تایپ کرده و از نتایج آن را انتخاب کنید.
- برای تأیید کمک هزینه نقش ، روی "ذخیره" کلیک کنید.
برای اطلاعات بیشتر در مورد این فرآیند به اسناد IAM مراجعه کنید ، یا یاد بگیرید که چگونه نقش ها را با استفاده از ابزارهای خط فرمان GCLOUD انجام دهید.
تعیین حساب خدمات انجام نشد
اگر پیام خطایی مشابه موارد زیر دریافت کنید ، SDK Admin Firebase به درستی اولیه نشده است.
Failed to determine service account ID. Initialize the SDK with service account credentials or specify a service account ID with iam.serviceAccounts.signBlob permission.
اگر برای کشف خودکار شناسه حساب خدمات به SDK تکیه می کنید ، مطمئن شوید که این کد در یک محیط Google مدیریت شده با یک سرور ابرداده مستقر شده است. در غیر این صورت ، حتماً در اولیه سازی SDK ، پرونده حساب JSON یا شناسه حساب خدمات را مشخص کنید.