Firebase, güvenli JSON Web Token'ları (JWT'ler) kullanarak kullanıcıların veya cihazların kimliğini doğrulamanıza olanak tanıyarak kimlik doğrulama üzerinde tam kontrol sahibi olmanızı sağlar. Bu jetonları sunucunuzda oluşturur, istemci cihazına geri aktarır ve ardından signInWithCustomToken()
yöntemiyle kimlik doğrulamak için kullanırsınız.
Bunu yapmak için, oturum açma kimlik bilgilerini (ör. kullanıcı adı ve şifre) kabul eden ve kimlik bilgileri geçerliyse özel bir JWT döndüren bir sunucu uç noktası oluşturmanız gerekir. Sunucunuzdan döndürülen özel JWT, istemci cihaz tarafından Firebase ile kimlik doğrulama yapmak için kullanılabilir (iOS+, Android, web). Kimlik doğrulaması yapılan bu kimlik, Firebase Realtime Database ve Cloud Storage gibi diğer Firebase hizmetlerine erişirken kullanılır. Ayrıca JWT'nin içeriği Realtime Database Security Rules içindeki auth
nesnesinde ve Cloud Storage Security Rules içindeki request.auth
nesnesinde kullanılabilir.
Firebase Admin SDK'sıyla özel jeton oluşturabilir veya sunucunuz Firebase'in doğal olarak desteklemediği bir dilde yazılmışsa üçüncü taraf bir JWT kitaplığı kullanabilirsiniz.
Başlamadan önce
Özel jetonlar, imzalama için kullanılan özel anahtarın bir Google hizmet hesabına ait olduğu imzalı JWT'lerdir. Özel jetonları imzalamak için Firebase Admin SDK'sı tarafından kullanılması gereken Google hizmet hesabını belirtmenin birkaç yolu vardır:
- Hizmet hesabı JSON dosyası kullanma: Bu yöntem her ortamda kullanılabilir ancak kodunuzla birlikte bir hizmet hesabı JSON dosyası paketlemenizi gerektirir. Hizmet hesabı JSON dosyasının harici taraflara açık olmaması için özel dikkat gösterilmelidir.
- Yönetici Konsolu SDK'sının bir hizmet hesabını keşfetmesine izin verme: Bu yöntem, Google Cloud Functions ve App Engine gibi Google tarafından yönetilen ortamlarda kullanılabilir. Bazı ek izinleri Google Cloud konsolu üzerinden yapılandırmanız gerekebilir.
- Hizmet hesabı kimliği kullanma -- Google tarafından yönetilen bir ortamda kullanıldığında bu yöntem, belirtilen hizmet hesabının anahtarını kullanarak jetonları imzalar. Ancak uzak bir web hizmeti kullandığından bu hizmet hesabı için Google Cloud konsolu üzerinden ek izinler yapılandırmanız gerekebilir.
Hizmet hesabı JSON dosyası kullanma
Hizmet hesabı JSON dosyaları, hizmet hesaplarına karşılık gelen tüm bilgileri içerir (RSA özel anahtarı dahil). Bu raporlar Firebase konsolundan indirilebilir. Yönetici SDK'sını bir hizmet hesabı JSON dosyasıyla başlatma hakkında daha fazla bilgi için Yönetici SDK'sı kurulum talimatlarını uygulayın.
Bu başlatma yöntemi, çok çeşitli Admin SDK dağıtımları için uygundur. Ayrıca, Admin SDK'nın uzak API çağrısı yapmadan yerel olarak özel jetonlar oluşturup imzalamasını sağlar. Bu yaklaşımın ana dezavantajı, kodunuzla birlikte bir hizmet hesabı JSON dosyasını paketlemenizi gerektirmesidir. Ayrıca, bir hizmet hesabı JSON dosyasındaki özel anahtarın hassas bilgiler olduğunu ve bu bilgilerin gizli tutulmasına özellikle dikkat edilmesi gerektiğini unutmayın. Özellikle, hizmet hesabı JSON dosyalarını herkese açık sürüm kontrolüne eklemekten kaçının.
Admin SDK'nın bir hizmet hesabını keşfetmesine izin verme
Kodunuz Google tarafından yönetilen bir ortamda dağıtılmışsa Yönetici SDK'sı, özel jetonları imzalamak için bir yöntemi otomatik olarak keşfetmeye çalışabilir:
Kodunuz Java, Python veya Go için App Engine standart ortamında dağıtılmışsa Yönetici SDK'sı, özel jetonları imzalamak için söz konusu ortamda bulunan uygulama kimliği hizmetini kullanabilir. Uygulama Kimliği hizmeti, Google App Engine tarafından uygulamanız için temel hazırlığı yapılan bir hizmet hesabını kullanarak verileri imzalar.
Kodunuz başka bir yönetilen ortamda (ör. Google Cloud Functions, Google Compute Engine) dağıtılmışsa Firebase Admin SDK'sı, yerel meta veri sunucusundan bir hizmet hesabı kimliği dizesini otomatik olarak keşfedebilir. Daha sonra, bulunan hizmet hesabı kimliği, jetonları uzaktan imzalamak için IAM hizmetiyle birlikte kullanılır.
Bu imzalama yöntemlerinden yararlanmak için SDK'yı Google Uygulama Varsayılan kimlik bilgileriyle başlatın ve hizmet hesabı kimliği dizesi belirtmeyin:
Node.js
initializeApp();
Java
FirebaseApp.initializeApp();
Python
default_app = firebase_admin.initialize_app()
Go
app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
log.Fatalf("error initializing app: %v\n", err)
}
C#
FirebaseApp.Create();
Aynı kodu yerel olarak test etmek için bir hizmet hesabı JSON dosyası indirin ve GOOGLE_APPLICATION_CREDENTIALS
ortam değişkenini bu dosyayı işaret edecek şekilde ayarlayın.
Firebase Admin SDK'sının bir hizmet hesabı kimliği dizesi keşfetmesi gerekiyorsa kodunuz ilk kez özel jeton oluşturduğunda bunu yapar. Sonuç önbelleğe alınır ve sonraki jeton imzalama işlemleri için yeniden kullanılır. Otomatik olarak keşfedilen hizmet hesabı kimliği genellikle Google Cloud tarafından sağlanan varsayılan hizmet hesaplarından biridir:
Açıkça belirtilen hizmet hesabı kimliklerinde olduğu gibi, özel jeton oluşturma işleminin çalışması için otomatik olarak keşfedilen hizmet hesabı kimliklerinin de iam.serviceAccounts.signBlob
iznine sahip olması gerekir. Varsayılan hizmet hesaplarına gerekli izinleri vermek için Google Cloud konsolunun IAM ve yönetici bölümünü kullanmanız gerekebilir. Daha fazla bilgi için aşağıdaki sorun giderme bölümüne bakın.
Hizmet hesabı kimliği kullanma
Uygulamanızın çeşitli bölümleri arasında tutarlılığı sağlamak amacıyla, Google tarafından yönetilen bir ortamda çalışırken anahtarları jetonları imzalamak için kullanılacak bir hizmet hesabı kimliği belirtebilirsiniz. Bu, IAM politikalarını daha basit ve daha güvenli hale getirebilir ve hizmet hesabı JSON dosyasını kodunuza eklemenizi önleyebilir.
Hizmet hesabı kimliğini Google Cloud konsolunda veya indirilen bir hizmet hesabı JSON dosyasının client_email
alanında bulabilirsiniz.
Hizmet hesabı kimlikleri, şu biçime sahip e-posta adresleridir:
<client-id>@<project-id>.iam.gserviceaccount.com
. Firebase ve Google Cloud projelerindeki hizmet hesaplarını benzersiz şekilde tanımlar.
Ayrı bir hizmet hesabı kimliği kullanarak özel jeton oluşturmak için SDK'yı aşağıda gösterildiği gibi başlatın:
Node.js
initializeApp({
serviceAccountId: 'my-client-id@my-project-id.iam.gserviceaccount.com',
});
Java
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(GoogleCredentials.getApplicationDefault())
.setServiceAccountId("my-client-id@my-project-id.iam.gserviceaccount.com")
.build();
FirebaseApp.initializeApp(options);
Python
options = {
'serviceAccountId': 'my-client-id@my-project-id.iam.gserviceaccount.com',
}
firebase_admin.initialize_app(options=options)
Go
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)
}
C#
FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.GetApplicationDefault(),
ServiceAccountId = "my-client-id@my-project-id.iam.gserviceaccount.com",
});
Hizmet hesabı kimlikleri hassas bilgiler olmadığından, bu kimliklerin açığa çıkması önemli değildir. Ancak belirtilen hizmet hesabıyla özel jetonlar imzalamak için Firebase Admin SDK'nın uzak bir hizmeti çağırması gerekir.
Ayrıca, Admin SDK'nın bu çağrıyı yapmak için kullandığı hizmet hesabının (genellikle {project-name}@appspot.gserviceaccount.com
) iam.serviceAccounts.signBlob
iznine sahip olduğundan da emin olmanız gerekir.
Daha fazla bilgi için aşağıdaki sorun giderme bölümüne bakın.
Firebase Admin SDK'sını kullanarak özel jeton oluşturma
Firebase Admin SDK'da, özel jetonlar oluşturmak için yerleşik bir yöntem bulunur. En azından, herhangi bir dize olabilecek ancak kimliğini doğruladığınız kullanıcıyı veya cihazı benzersiz bir şekilde tanımlaması gereken bir uid
girmeniz gerekir. Bu jetonların süresi bir saat sonra dolar.
Node.js
const uid = 'some-uid';
getAuth()
.createCustomToken(uid)
.then((customToken) => {
// Send token back to client
})
.catch((error) => {
console.log('Error creating custom token:', error);
});
Java
String uid = "some-uid";
String customToken = FirebaseAuth.getInstance().createCustomToken(uid);
// Send token back to client
Python
uid = 'some-uid'
custom_token = auth.create_custom_token(uid)
Go
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)
C#
var uid = "some-uid";
string customToken = await FirebaseAuth.DefaultInstance.CreateCustomTokenAsync(uid);
// Send token back to client
İsteğe bağlı olarak özel jetona eklenecek ek iddialar da belirtebilirsiniz. Örneğin, aşağıda, Güvenlik Kurallarınızdaki auth
/ request.auth
nesnelerinde bulunacak özel jetona bir premiumAccount
alanı eklendi:
Node.js
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);
});
Java
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
Python
uid = 'some-uid'
additional_claims = {
'premiumAccount': True
}
custom_token = auth.create_custom_token(uid, additional_claims)
Go
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)
C#
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
Ayrılmış özel jeton adları
İstemcilerde özel jetonları kullanarak oturum açma
Özel jeton oluşturduktan sonra bunu istemci uygulamanıza göndermeniz gerekir. İstemci uygulaması, signInWithCustomToken()
çağrısını yaparak özel jetonla kimlik doğrulaması yapar:
iOS ve üzeri
Objective-C
[[FIRAuth auth] signInWithCustomToken:customToken
completion:^(FIRAuthDataResult * _Nullable authResult,
NSError * _Nullable error) {
// ...
}];
Swift
Auth.auth().signIn(withCustomToken: customToken ?? "") { user, error in
// ...
}
Android
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);
}
}
});
Unity
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);
});
C++
firebase::Future<firebase::auth::AuthResult> result =
auth->SignInWithCustomToken(custom_token);
Web
firebase.auth().signInWithCustomToken(token)
.then((userCredential) => {
// Signed in
var user = userCredential.user;
// ...
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
Web
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;
// ...
});
Kimlik doğrulama başarılı olursa kullanıcınız, özel jetona dahil edilen uid
tarafından belirtilen hesapla istemci uygulamanızda oturum açar. Bu hesap daha önce mevcut değilse bu kullanıcı için bir kayıt oluşturulur.
Diğer oturum açma yöntemlerinde (signInWithEmailAndPassword()
ve signInWithCredential()
gibi) olduğu gibi, Realtime Database Security Rules öğenizdeki auth
ve Cloud Storage Security Rules öğenizdeki request.auth
, kullanıcının uid
ile doldurulur. Bu durumda, uid
, özel jetonu oluştururken belirttiğiniz veri olacaktır.
Veritabanı Kuralları
{
"rules": {
"adminContent": {
".read": "auth.uid === 'some-uid'"
}
}
}
Depolama Kuralları
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";
}
}
}
Özel jeton ek iddialar içeriyorsa bu iddialara, kurallarınızdaki auth.token
(Firebase Realtime Database) veya request.auth.token
(Cloud Storage) nesnesinden referans verilebilir:
Veritabanı Kuralları
{
"rules": {
"premiumContent": {
".read": "auth.token.premiumAccount === true"
}
}
}
Depolama Kuralları
service firebase.storage {
match /b/<your-firebase-storage-bucket>/o {
match /premiumContent/{filename} {
allow read, write: if request.auth.token.premiumAccount == true;
}
}
}
Üçüncü taraf JWT kitaplığı kullanarak özel jeton oluşturma
Arka uçunuz, resmi bir Firebase Yönetici SDK'sı bulunmayan bir dildeyse yine de özel jetonları manuel olarak oluşturabilirsiniz. Öncelikle, diliniz için üçüncü taraf JWT kitaplığı bulun. Ardından, aşağıdaki hak taleplerini içeren bir JWT oluşturmak için bu JWT kitaplığını kullanın:
Özel jeton talepleri | ||
---|---|---|
alg |
Algoritma | "RS256" |
iss |
Düzenleyen | Projenizin hizmet hesabı e-posta adresi |
sub |
Konu | Projenizin hizmet hesabı e-posta adresi |
aud |
Kitle | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat |
Yayınlanma zamanı | UNIX döneminden bu yana geçen saniye cinsinden geçerli zaman |
exp |
Geçerlilik süresi |
UNIX sıfır zamanından itibaren saniye cinsinden jetonun geçerlilik süresinin sona erdiği zaman. Bu, iat değerinden en fazla 3.600 saniye sonra olabilir.
Not: Bu ayar yalnızca özel jetonun süresinin sona erdiği zamanı kontrol eder. Ancak signInWithCustomToken() kullanarak bir kullanıcının oturumunu açtıktan sonra, oturumu geçersiz kılınana veya kullanıcı oturumu kapatana kadar cihazda oturumu açık kalır.
|
uid |
Oturum açmış kullanıcının benzersiz tanımlayıcısı, 1 ila 128 karakter uzunluğunda bir dize olmalıdır. Daha kısa uid 'ler daha iyi performans sunar.
|
|
claims (isteğe bağlı) |
Güvenlik Kuralları auth /request.auth değişkenlerine dahil edilecek isteğe bağlı özel hak talepleri
|
Firebase Admin SDK'sının desteklemediği çeşitli dillerde özel jeton oluşturma ile ilgili bazı örnek uygulamalar aşağıda verilmiştir:
PHP
php-jwt
kullanılıyor:
// 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
ruby-jwt
kullanılıyor:
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
Özel jetonu oluşturduktan sonra Firebase ile kimlik doğrulama yapmak için istemci uygulamanıza gönderin. Bunu nasıl yapacağınız hakkında bilgi edinmek için yukarıdaki kod örneklerine bakın.
Sorun giderme
Bu bölümde, geliştiricilerin özel jeton oluştururken karşılaşabileceği bazı yaygın sorunlar ve bunların nasıl çözüleceği açıklanmaktadır.
IAM API etkin değil
İmzalama jetonları için bir hizmet hesabı kimliği belirtiyorsanız aşağıdakine benzer bir hata alabilirsiniz:
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'sı, jetonları imzalamak için IAM API'yi kullanır. Bu hata, IAM API'nin şu anda Firebase projeniz için etkinleştirilmediğini gösterir. Hata mesajındaki bağlantıyı bir web tarayıcısında açın ve projenizde etkinleştirmek için "API'yi etkinleştir" düğmesini tıklayın.
Hizmet hesabının gerekli izinleri yok
Firebase Admin SDK'nın çalıştırdığı hizmet hesabında iam.serviceAccounts.signBlob
izni yoksa aşağıdaki gibi bir hata mesajı alabilirsiniz:
Permission iam.serviceAccounts.signBlob is required to perform this operation on service account projects/-/serviceAccounts/{your-service-account-id}.
Bu sorunu çözmenin en kolay yolu, söz konusu hizmet hesabına (genellikle {project-name}@appspot.gserviceaccount.com
) "Hizmet Hesabı Jeton Oluşturucu" IAM rolünü vermektir:
- Google Cloud konsolunda IAM ve yönetici sayfasını açın.
- Projenizi seçin ve "Continue" (Devam) düğmesini tıklayın.
- Güncellemek istediğiniz hizmet hesabına karşılık gelen düzenle simgesini tıklayın.
- "Başka bir rol ekle"yi tıklayın.
- Arama filtresine "Service Account Token Creator" (Hizmet Hesabı Jetonu Oluşturucu) yazın ve sonuçlar arasından bunu seçin.
- Rol atamasını onaylamak için "Kaydet"i tıklayın.
Bu süreçle ilgili daha fazla bilgi için IAM belgelerini inceleyin veya gcloud komut satırı araçlarını kullanarak rolleri güncelleme hakkında bilgi edinin.
Hizmet hesabı belirlenemedi
Aşağıdakine benzer bir hata mesajı alırsanız Firebase Admin SDK'sı doğru şekilde başlatılmamıştır.
Failed to determine service account ID. Initialize the SDK with service account credentials or specify a service account ID with iam.serviceAccounts.signBlob permission.
Bir hizmet hesabı kimliğini otomatik olarak keşfetmek için SDK'yı kullanıyorsanız kodun, meta veri sunucusu olan yönetilen bir Google ortamına dağıtıldığından emin olun. Aksi takdirde, SDK başlatılırken hizmet hesabı JSON dosyasını veya hizmet hesabı kimliğini belirttiğinizden emin olun.