Google is committed to advancing racial equity for Black communities. See how.
Bu sayfa, Cloud Translation API ile çevrilmiştir.
Switch to English

Özel Hak Talepleri ve Güvenlik Kuralları ile Erişimi Kontrol Edin

Firebase Yönetici SDK'sı, kullanıcı hesaplarında özel özellikler tanımlamayı destekler. Bu, Firebase uygulamalarında role dayalı erişim kontrolü de dahil olmak üzere çeşitli erişim kontrolü stratejilerini uygulama yeteneği sağlar. Bu özel öznitelikler, kullanıcılara uygulamanın güvenlik kurallarında uygulanan farklı erişim düzeyleri (roller) verebilir.

Kullanıcı rolleri aşağıdaki yaygın durumlar için tanımlanabilir:

  • Verilere ve kaynaklara erişmek için kullanıcıya yönetici ayrıcalıkları verme.
  • Bir kullanıcının ait olduğu farklı grupları tanımlama.
  • Çok seviyeli erişim sağlama:
    • Ücretli / ücretsiz abonelerin farklılaştırılması.
    • Moderatörleri normal kullanıcılardan ayırma.
    • Öğretmen / öğrenci başvurusu vb.
  • Kullanıcıya ek bir tanımlayıcı ekleyin. Örneğin, bir Firebase kullanıcısı başka bir sistemdeki farklı bir UID ile eşleşebilir.

"AdminContent" veritabanı düğümüne erişimi sınırlamak istediğiniz durumu ele alalım. Bunu, yönetici kullanıcıları listesinde veritabanı aramasıyla yapabilirsiniz. Ancak, aşağıdaki Realtime Database kuralına sahip admin adında özel bir kullanıcı talebi kullanarak aynı hedefe daha verimli bir şekilde ulaşabilirsiniz:

 {
  "rules": {
    "adminContent": {
      ".read": "auth.token.admin === true",
      ".write": "auth.token.admin === true",
    }
  }
}
 

Özel kullanıcı hak taleplerine kullanıcının kimlik doğrulama simgeleriyle erişilebilir. Yukarıdaki örnekte, sadece kullanıcıların admin kendi belirteç istem true seti / yazma erişimi okurdu adminContent düğümü. Kimlik jetonu bu iddiaları zaten içerdiğinden, yönetici izinlerini kontrol etmek için ek işleme veya aramaya gerek yoktur. Ek olarak, kimlik belirteci bu özel talepleri yerine getirmek için güvenilir bir mekanizmadır. Kimliği doğrulanmış tüm erişim, ilişkili isteği işlemeden önce kimlik jetonunu doğrulamalıdır.

Bu sayfada açıklanan kod örnekleri ve çözümleri, hem istemci tarafı Firebase Kimlik Doğrulama API'lerinden hem de Yönetici SDK tarafından sağlanan sunucu tarafı Kimlik Doğrulama API'lerinden alınmıştır.

Yönetici SDK'sı üzerinden özel kullanıcı taleplerini ayarlama ve doğrulama

Özel hak talepleri hassas veriler içerebilir, bu nedenle yalnızca Firebase Yönetici SDK'sı tarafından ayrıcalıklı bir sunucu ortamından ayarlanmalıdır.

node.js

 // Set admin privilege on the user corresponding to uid.

admin.auth().setCustomUserClaims(uid, {admin: true}).then(() => {
  // The new custom claims will propagate to the user's ID token the
  // next time a new one is issued.
});
 

Java

 // Set admin privilege on the user corresponding to uid.
Map<String, Object> claims = new HashMap<>();
claims.put("admin", true);
FirebaseAuth.getInstance().setCustomUserClaims(uid, claims);
// The new custom claims will propagate to the user's ID token the
// next time a new one is issued.
 

piton

 # Set admin privilege on the user corresponding to uid.
auth.set_custom_user_claims(uid, {'admin': True})
# The new custom claims will propagate to the user's ID token the
# next time a new one is issued.
 

Git

 // Get an auth client from the firebase.App
client, err := app.Auth(ctx)
if err != nil {
	log.Fatalf("error getting Auth client: %v\n", err)
}

// Set admin privilege on the user corresponding to uid.
claims := map[string]interface{}{"admin": true}
err = client.SetCustomUserClaims(ctx, uid, claims)
if err != nil {
	log.Fatalf("error setting custom claims %v\n", err)
}
// The new custom claims will propagate to the user's ID token the
// next time a new one is issued. 

C #

 // Set admin privileges on the user corresponding to uid.
var claims = new Dictionary<string, object>()
{
    { "admin", true },
};
await FirebaseAuth.DefaultInstance.SetCustomUserClaimsAsync(uid, claims);
// The new custom claims will propagate to the user's ID token the
// next time a new one is issued.
 

Özel talepler nesnesi OIDC ayrılmış anahtar adı veya Firebase ayrılmış adı içermemelidir. Özel talep yükü 1000 baytı aşmamalıdır.

Arka uç sunucusuna gönderilen bir kimlik belirteci, Yönetici SDK'sını kullanarak kullanıcının kimliğini ve erişim düzeyini aşağıdaki gibi doğrulayabilir:

node.js

 // Verify the ID token first.
admin.auth().verifyIdToken(idToken).then((claims) => {
  if (claims.admin === true) {
    // Allow access to requested admin resource.
  }
});
 

Java

 // Verify the ID token first.
FirebaseToken decoded = FirebaseAuth.getInstance().verifyIdToken(idToken);
if (Boolean.TRUE.equals(decoded.getClaims().get("admin"))) {
  // Allow access to requested admin resource.
}
 

piton

 # Verify the ID token first.
claims = auth.verify_id_token(id_token)
if claims['admin'] is True:
    # Allow access to requested admin resource.
    pass
 

Git

 // Verify the ID token first.
token, err := client.VerifyIDToken(ctx, idToken)
if err != nil {
	log.Fatal(err)
}

claims := token.Claims
if admin, ok := claims["admin"]; ok {
	if admin.(bool) {
		//Allow access to requested admin resource.
	}
} 

C #

 // Verify the ID token first.
FirebaseToken decoded = await FirebaseAuth.DefaultInstance.VerifyIdTokenAsync(idToken);
object isAdmin;
if (decoded.Claims.TryGetValue("admin", out isAdmin))
{
    if ((bool)isAdmin)
    {
        // Allow access to requested admin resource.
    }
}

 

Bir kullanıcının, kullanıcı nesnesinde özellik olarak bulunan mevcut özel hak taleplerini de kontrol edebilirsiniz:

node.js

 // Lookup the user associated with the specified uid.
admin.auth().getUser(uid).then((userRecord) => {
  // The claims can be accessed on the user record.
  console.log(userRecord.customClaims['admin']);
});
 

Java

 // Lookup the user associated with the specified uid.
UserRecord user = FirebaseAuth.getInstance().getUser(uid);
System.out.println(user.getCustomClaims().get("admin"));
 

piton

 # Lookup the user associated with the specified uid.
user = auth.get_user(uid)
# The claims can be accessed on the user record.
print(user.custom_claims.get('admin'))
 

Git

 // Lookup the user associated with the specified uid.
user, err := client.GetUser(ctx, uid)
if err != nil {
	log.Fatal(err)
}
// The claims can be accessed on the user record.
if admin, ok := user.CustomClaims["admin"]; ok {
	if admin.(bool) {
		log.Println(admin)
	}
} 

C #

 // Lookup the user associated with the specified uid.
UserRecord user = await FirebaseAuth.DefaultInstance.GetUserAsync(uid);
Console.WriteLine(user.CustomClaims["admin"]);
 

customClaims için null ileterek kullanıcının özel hak taleplerini customClaims .

Özel talepleri müşteriye yayma

Bir kullanıcı üzerinde Yönetici SDK'sı aracılığıyla yeni hak talepleri değiştirildikten sonra, kimlik belirteci aracılığıyla kimliği doğrulanmış bir kullanıcıya kimlik belirteci aracılığıyla aşağıdaki şekillerde yayılır:

  • Bir kullanıcı, özel hak talepleri değiştirildikten sonra oturum açar veya yeniden doğrular. Sonuç olarak verilen kimlik jetonu en son talepleri içerecektir.
  • Varolan bir kullanıcı oturumu, daha eski bir belirtecin süresi dolduktan sonra kimlik belirtecinin yenilenmesini sağlar.
  • Kuvvet token bir kimlik çağırarak yenilenir currentUser.getIdToken(true) .

İstemcideki özel hak taleplerine erişin

Özel hak talepleri yalnızca kullanıcının kimlik belirteciyle alınabilir. İstemci kullanıcı arayüzünü kullanıcının rolüne veya erişim düzeyine göre değiştirmek için bu hak taleplerine erişim gerekebilir. Ancak, arka uç erişimi, kimlik doğrulaması ve iddialarının ayrıştırılmasından sonra her zaman kimlik belirteciyle uygulanmalıdır. Özel hak talepleri, jetonun dışında güvenilemediği için doğrudan arka uca gönderilmemelidir.

En son talepler bir kullanıcının kimlik jetonuna yayıldıktan sonra, kimlik jetonunu alarak bunları alabilirsiniz:

JavaScript

 firebase.auth().currentUser.getIdTokenResult()
  .then((idTokenResult) => {
     // Confirm the user is an Admin.
     if (!!idTokenResult.claims.admin) {
       // Show admin UI.
       showAdminUI();
     } else {
       // Show regular user UI.
       showRegularUI();
     }
  })
  .catch((error) => {
    console.log(error);
  });
 

Android

 user.getIdToken(false).addOnSuccessListener(new OnSuccessListener<GetTokenResult>() {
  @Override
  public void onSuccess(GetTokenResult result) {
    boolean isAdmin = result.getClaims().get("admin");
    if (isAdmin) {
      // Show admin UI.
      showAdminUI();
    } else {
      // Show regular user UI.
      showRegularUI();
    }
  }
});
 

hızlı

 user.getIDTokenResult(completion: { (result, error) in
  guard let admin = result?.claims?["admin"] as? NSNumber else {
    // Show regular user UI.
    showRegularUI()
    return
  }
  if admin.boolValue {
    // Show admin UI.
    showAdminUI()
  } else {
    // Show regular user UI.
    showRegularUI()
  }
})
 

Objective-C

 user.getIDTokenResultWithCompletion:^(FIRAuthTokenResult *result,
                                      NSError *error) {
  if (error != nil) {
    BOOL *admin = [result.claims[@"admin"] boolValue];
    if (admin) {
      // Show admin UI.
      [self showAdminUI];
    } else {
      // Show regular user UI.
      [self showRegularUI];
    }
  }
}];
 

Özel hak talepleri için en iyi uygulamalar

Özel hak talepleri yalnızca erişim kontrolü sağlamak için kullanılır. Ek verileri (profil ve diğer özel veriler gibi) depolamak için tasarlanmamıştır. Bu, bunu yapmak için uygun bir mekanizma gibi görünse de, bu hak talepleri kimlik belirtecinde saklandığından ve performans sorunlarına neden olabileceğinden kesinlikle önerilmez, çünkü tüm kimliği doğrulanmış istekler her zaman oturum açan kullanıcıya karşılık gelen bir Firebase Kimlik belirteci içerir.

  • Yalnızca kullanıcı erişimini denetlemek amacıyla verileri depolamak için özel hak taleplerini kullanın. Diğer tüm veriler, gerçek zamanlı veritabanı veya diğer sunucu tarafı depolaması yoluyla ayrı olarak saklanmalıdır.
  • Özel taleplerin boyutu sınırlıdır. 1000 bayttan büyük bir özel talep yükü iletmek hataya neden olur.

Örnekler ve kullanım örnekleri

Aşağıdaki örnekler, belirli Firebase kullanım örnekleri bağlamında özel talepleri göstermektedir.

Kullanıcı oluşturmada Firebase İşlevleri aracılığıyla rolleri tanımlama

Bu örnekte, özel işlevler kullanıcı üzerinde Bulut İşlevleri kullanılarak oluşturma konusunda ayarlanır.

Özel hak talepleri Bulut İşlevleri kullanılarak eklenebilir ve hemen Gerçek Zamanlı Veritabanı ile çoğaltılabilir. İşlevi kullanan tek kayıt üzerinde denir onCreate tetiği. Özel talepler belirlendikten sonra, mevcut ve gelecekteki tüm oturumlara yayılırlar. Kullanıcı, kullanıcı kimlik bilgisiyle bir sonraki oturum açışında simge özel talepleri içerir.

İstemci tarafı uygulaması (JavaScript)

 const provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider)
.catch(error => {
  console.log(error);
});

let callback = null;
let metadataRef = null;
firebase.auth().onAuthStateChanged(user => {
  // Remove previous listener.
  if (callback) {
    metadataRef.off('value', callback);
  }
  // On user login add new listener.
  if (user) {
    // Check if refresh is required.
    metadataRef = firebase.database().ref('metadata/' + user.uid + '/refreshTime');
    callback = (snapshot) => {
      // Force refresh to pick up the latest custom claims changes.
      // Note this is always triggered on first call. Further optimization could be
      // added to avoid the initial trigger when the token is issued and already contains
      // the latest claims.
      user.getIdToken(true);
    };
    // Subscribe new listener to changes on that node.
    metadataRef.on('value', callback);
  }
});
 

Bulut İşlevleri mantığı

Kimliği doğrulanmış kullanıcıyla okuma / yazma kısıtlaması olan yeni bir veritabanı düğümü (meta veri / ($ uid)} eklenir.

 const functions = require('firebase-functions');

const admin = require('firebase-admin');
admin.initializeApp();

// On sign up.
exports.processSignUp = functions.auth.user().onCreate((user) => {
  // Check if user meets role criteria.
  if (user.email &&
      user.email.endsWith('@admin.example.com') &&
      user.emailVerified) {
    const customClaims = {
      admin: true,
      accessLevel: 9
    };
    // Set custom user claims on this newly created user.
    return admin.auth().setCustomUserClaims(user.uid, customClaims)
      .then(() => {
        // Update real-time database to notify client to force refresh.
        const metadataRef = admin.database().ref("metadata/" + user.uid);
        // Set the refresh time to the current UTC timestamp.
        // This will be captured on the client to force a token refresh.
        return metadataRef.set({refreshTime: new Date().getTime()});
      })
      .catch(error => {
        console.log(error);
      });
  }
});
 

Veritabanı kuralları

 {
  "rules": {
    "metadata": {
      "$user_id": {
        // Read access only granted to the authenticated user.
        ".read": "$user_id === auth.uid",
        // Write access only via Admin SDK.
        ".write": false
      }
    }
  }
}
 

HTTP isteği yoluyla rol tanımlama

Aşağıdaki örnek, yeni oturum açmış bir kullanıcının HTTP isteği yoluyla özel kullanıcı taleplerini ayarlar.

İstemci tarafı uygulaması (JavaScript)

 const provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider)
.then((result) => {
  // User is signed in. Get the ID token.
  return result.user.getIdToken();
})
.then((idToken) => {
  // Pass the ID token to the server.
  $.post(
    '/setCustomClaims',
    {
      idToken: idToken
    },
    (data, status) => {
      // This is not required. You could just wait until the token is expired
      // and it proactively refreshes.
      if (status == 'success' && data) {
        const json = JSON.parse(data);
        if (json && json.status == 'success') {
          // Force token refresh. The token claims will contain the additional claims.
          firebase.auth().currentUser.getIdToken(true);
        }
      }
    });
}).catch((error) => {
  console.log(error);
});
 

Arka uç uygulaması (Yönetici SDK'sı)

 app.post('/setCustomClaims', (req, res) => {
  // Get the ID token passed.
  const idToken = req.body.idToken;
  // Verify the ID token and decode its payload.
  admin.auth().verifyIdToken(idToken).then((claims) => {
    // Verify user is eligible for additional privileges.
    if (typeof claims.email !== 'undefined' &&
        typeof claims.email_verified !== 'undefined' &&
        claims.email_verified &&
        claims.email.endsWith('@admin.example.com')) {
      // Add custom claims for additional privileges.
      admin.auth().setCustomUserClaims(claims.sub, {
        admin: true
      }).then(function() {
        // Tell client to refresh token on user.
        res.end(JSON.stringify({
          status: 'success'
        });
      });
    } else {
      // Return nothing.
      res.end(JSON.stringify({status: 'ineligible'});
    }
  });
});
 

Aynı akış mevcut bir kullanıcının erişim düzeyini yükseltirken de kullanılabilir. Örneğin ücretli bir aboneliğe yükseltme yapan ücretsiz bir kullanıcı. Kullanıcının kimlik belirteci, ödeme bilgileriyle birlikte bir HTTP isteği yoluyla arka uç sunucusuna gönderilir. Ödeme başarıyla işleme koyulduğunda, kullanıcı Yönetici SDK'sı üzerinden ücretli bir abone olarak ayarlanır. Belirteç yenilemeyi zorlamak için istemciye başarılı bir HTTP yanıtı döndürülür.

Arka uç komut dosyası aracılığıyla rolleri tanımlama

Yinelenen bir komut dosyası (istemciden başlatılmayan), kullanıcı özel hak taleplerini güncellemek üzere çalıştırılacak şekilde ayarlanabilir:

node.js

 admin.auth().getUserByEmail('user@admin.example.com').then((user) => {
  // Confirm user is verified.
  if (user.emailVerified) {
    // Add custom claims for additional privileges.
    // This will be picked up by the user on token refresh or next sign in on new device.
    return admin.auth().setCustomUserClaims(user.uid, {
      admin: true
    });
  }
})
  .catch((error) => {
    console.log(error);
  });
 

Java

 UserRecord user = FirebaseAuth.getInstance()
    .getUserByEmail("user@admin.example.com");
// Confirm user is verified.
if (user.isEmailVerified()) {
  Map<String, Object> claims = new HashMap<>();
  claims.put("admin", true);
  FirebaseAuth.getInstance().setCustomUserClaims(user.getUid(), claims);
}
 

piton

 user = auth.get_user_by_email('user@admin.example.com')
# Confirm user is verified
if user.email_verified:
    # Add custom claims for additional privileges.
    # This will be picked up by the user on token refresh or next sign in on new device.
    auth.set_custom_user_claims(user.uid, {
        'admin': True
    })
 

Git

 user, err := client.GetUserByEmail(ctx, "user@admin.example.com")
if err != nil {
	log.Fatal(err)
}
// Confirm user is verified
if user.EmailVerified {
	// Add custom claims for additional privileges.
	// This will be picked up by the user on token refresh or next sign in on new device.
	err := client.SetCustomUserClaims(ctx, user.UID, map[string]interface{}{"admin": true})
	if err != nil {
		log.Fatalf("error setting custom claims %v\n", err)
	}

} 

C #

 UserRecord user = await FirebaseAuth.DefaultInstance
    .GetUserByEmailAsync("user@admin.example.com");
// Confirm user is verified.
if (user.EmailVerified)
{
    var claims = new Dictionary<string, object>()
    {
        { "admin", true },
    };
    await FirebaseAuth.DefaultInstance.SetCustomUserClaimsAsync(user.Uid, claims);
}

 

Özel hak talepleri ayrıca Yönetici SDK'sı aracılığıyla aşamalı olarak değiştirilebilir:

node.js

 admin.auth().getUserByEmail('user@admin.example.com').then((user) => {
  // Add incremental custom claim without overwriting existing claims.
  const currentCustomClaims = user.customClaims;
  if (currentCustomClaims['admin']) {
    // Add level.
    currentCustomClaims['accessLevel'] = 10;
    // Add custom claims for additional privileges.
    return admin.auth().setCustomUserClaims(user.uid, currentCustomClaims);
  }
})
  .catch((error) => {
    console.log(error);
  });
 

Java

 UserRecord user = FirebaseAuth.getInstance()
    .getUserByEmail("user@admin.example.com");
// Add incremental custom claim without overwriting the existing claims.
Map<String, Object> currentClaims = user.getCustomClaims();
if (Boolean.TRUE.equals(currentClaims.get("admin"))) {
  // Add level.
  currentClaims.put("level", 10);
  // Add custom claims for additional privileges.
  FirebaseAuth.getInstance().setCustomUserClaims(user.getUid(), currentClaims);
}
 

piton

 user = auth.get_user_by_email('user@admin.example.com')
# Add incremental custom claim without overwriting existing claims.
current_custom_claims = user.custom_claims
if current_custom_claims.get('admin'):
    # Add level.
    current_custom_claims['accessLevel'] = 10
    # Add custom claims for additional privileges.
    auth.set_custom_user_claims(user.uid, current_custom_claims)
 

Git

 user, err := client.GetUserByEmail(ctx, "user@admin.example.com")
if err != nil {
	log.Fatal(err)
}
// Add incremental custom claim without overwriting existing claims.
currentCustomClaims := user.CustomClaims
if currentCustomClaims == nil {
	currentCustomClaims = map[string]interface{}{}
}

if _, found := currentCustomClaims["admin"]; found {
	// Add level.
	currentCustomClaims["accessLevel"] = 10
	// Add custom claims for additional privileges.
	err := client.SetCustomUserClaims(ctx, user.UID, currentCustomClaims)
	if err != nil {
		log.Fatalf("error setting custom claims %v\n", err)
	}

} 

C #

 UserRecord user = await FirebaseAuth.DefaultInstance
    .GetUserByEmailAsync("user@admin.example.com");
// Add incremental custom claims without overwriting the existing claims.
object isAdmin;
if (user.CustomClaims.TryGetValue("admin", out isAdmin) && (bool)isAdmin)
{
    var claims = new Dictionary<string, object>(user.CustomClaims);
    // Add level.
    claims["level"] = 10;
    // Add custom claims for additional privileges.
    await FirebaseAuth.DefaultInstance.SetCustomUserClaimsAsync(user.Uid, claims);
}