Google 致力于为黑人社区推动种族平等。查看具体举措
หน้านี้ได้รับการแปลโดย Cloud Translation API
Switch to English

ควบคุมการเข้าถึงด้วยการอ้างสิทธิ์ที่กำหนดเองและกฎความปลอดภัย

Firebase Admin SDK รองรับการกำหนดแอตทริบิวต์ที่กำหนดเองในบัญชีผู้ใช้ สิ่งนี้ช่วยให้สามารถใช้กลยุทธ์การควบคุมการเข้าถึงต่างๆรวมถึงการควบคุมการเข้าถึงตามบทบาทในแอป Firebase แอตทริบิวต์ที่กำหนดเองเหล่านี้สามารถให้ผู้ใช้เข้าถึงระดับต่างๆ (บทบาท) ซึ่งบังคับใช้ในกฎความปลอดภัยของแอปพลิเคชัน

สามารถกำหนดบทบาทของผู้ใช้สำหรับกรณีทั่วไปดังต่อไปนี้:

  • ให้สิทธิ์ผู้ดูแลระบบผู้ใช้ในการเข้าถึงข้อมูลและทรัพยากร
  • การกำหนดกลุ่มต่างๆที่ผู้ใช้เป็นสมาชิก
  • ให้การเข้าถึงหลายระดับ:
    • การสร้างความแตกต่างของสมาชิกที่ชำระเงิน / ไม่ได้ชำระเงิน
    • สร้างความแตกต่างระหว่างผู้ดูแลจากผู้ใช้ทั่วไป
    • ใบสมัครครู / นักเรียน ฯลฯ
  • เพิ่มตัวระบุเพิ่มเติมสำหรับผู้ใช้ ตัวอย่างเช่นผู้ใช้ Firebase สามารถแมปกับ UID อื่นในระบบอื่นได้

ลองพิจารณากรณีที่คุณต้องการ จำกัด การเข้าถึงโหนดฐานข้อมูล "adminContent" คุณสามารถทำได้ด้วยการค้นหาฐานข้อมูลในรายชื่อผู้ดูแลระบบ อย่างไรก็ตามคุณสามารถบรรลุวัตถุประสงค์เดียวกันได้อย่างมีประสิทธิภาพมากขึ้นโดยใช้การอ้างสิทธิ์ของผู้ใช้ที่กำหนดเองชื่อ admin ด้วยกฎฐานข้อมูลแบบเรียลไทม์ต่อไปนี้:

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

การอ้างสิทธิ์ของผู้ใช้แบบกำหนดเองสามารถเข้าถึงได้ผ่านโทเค็นการตรวจสอบสิทธิ์ของผู้ใช้ ในตัวอย่างข้างต้นมีเพียงผู้ใช้ที่ผู้ admin ตั้งค่าเป็น true ในการอ้างสิทธิ์โทเค็นเท่านั้นที่จะมีสิทธิ์เข้าถึงโหนด adminContent อ่าน / เขียน เนื่องจากโทเค็น ID มีการยืนยันเหล่านี้อยู่แล้วจึงไม่จำเป็นต้องมีการประมวลผลหรือการค้นหาเพิ่มเติมเพื่อตรวจสอบสิทธิ์ของผู้ดูแลระบบ นอกจากนี้โทเค็นรหัสยังเป็นกลไกที่เชื่อถือได้ในการส่งการอ้างสิทธิ์ที่กำหนดเองเหล่านี้ การเข้าถึงที่พิสูจน์ตัวตนทั้งหมดต้องตรวจสอบความถูกต้องของโทเค็น ID ก่อนที่จะประมวลผลคำขอที่เกี่ยวข้อง

ตัวอย่างโค้ดและโซลูชันที่อธิบายในหน้านี้มาจากทั้ง Firebase Auth API ฝั่งไคลเอ็นต์และ Auth APIs ฝั่งเซิร์ฟเวอร์ที่ Admin SDK จัดเตรียมไว้ให้

ตั้งค่าและตรวจสอบการอ้างสิทธิ์ของผู้ใช้ที่กำหนดเองผ่าน Admin SDK

การอ้างสิทธิ์ที่กำหนดเองอาจมีข้อมูลที่ละเอียดอ่อนดังนั้นจึงควรตั้งค่าจากสภาพแวดล้อมเซิร์ฟเวอร์ที่มีสิทธิ์โดย Firebase Admin SDK

โหนด 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.

Python

# 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.

ไป

// 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.

ค#

// 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.

ออบเจ็กต์การอ้างสิทธิ์ที่กำหนดเองไม่ควรมีชื่อคีย์ที่สงวนไว้ OIDC หรือชื่อที่สงวนไว้ของ Firebase เพย์โหลดการอ้างสิทธิ์ที่กำหนดเองต้องไม่เกิน 1,000 ไบต์

โทเค็น ID ที่ส่งไปยังเซิร์ฟเวอร์แบ็กเอนด์สามารถยืนยันตัวตนของผู้ใช้และระดับการเข้าถึงโดยใช้ Admin SDK ดังต่อไปนี้:

โหนด 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.
}

Python

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

ไป

// 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.
	}
}

ค#

// 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.
    }
}

คุณยังสามารถตรวจสอบการอ้างสิทธิ์ที่กำหนดเองที่มีอยู่ของผู้ใช้ซึ่งพร้อมใช้งานเป็นคุณสมบัติในออบเจ็กต์ผู้ใช้:

โหนด 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"));

Python

# 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'))

ไป

// 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)
	}
}

ค#

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

คุณสามารถลบการอ้างสิทธิ์ที่กำหนดเองของผู้ใช้โดยส่งค่า null สำหรับ customClaims

เผยแพร่การอ้างสิทธิ์ที่กำหนดเองให้กับลูกค้า

หลังจากแก้ไขการอ้างสิทธิ์ใหม่สำหรับผู้ใช้ผ่าน Admin SDK แล้วการอ้างสิทธิ์เหล่านี้จะถูกเผยแพร่ไปยังผู้ใช้ที่ได้รับการพิสูจน์ตัวตนในฝั่งไคลเอ็นต์ผ่านทางโทเค็น ID ด้วยวิธีต่อไปนี้:

  • ผู้ใช้ลงชื่อเข้าใช้หรือตรวจสอบสิทธิ์อีกครั้งหลังจากแก้ไขการอ้างสิทธิ์ที่กำหนดเองแล้ว โทเค็น ID ที่ออกให้จะมีการอ้างสิทธิ์ล่าสุด
  • เซสชันของผู้ใช้ที่มีอยู่จะได้รับโทเค็น ID ที่รีเฟรชหลังจากโทเค็นรุ่นเก่าหมดอายุ
  • โทเค็น ID ถูกบังคับให้รีเฟรชโดยการเรียก currentUser.getIdToken(true)

เข้าถึงการอ้างสิทธิ์ที่กำหนดเองบนไคลเอนต์

การอ้างสิทธิ์ที่กำหนดเองสามารถเรียกได้ผ่านโทเค็น ID ของผู้ใช้เท่านั้น การเข้าถึงการอ้างสิทธิ์เหล่านี้อาจจำเป็นเพื่อแก้ไข UI ไคลเอนต์ตามบทบาทหรือระดับการเข้าถึงของผู้ใช้ อย่างไรก็ตามควรบังคับใช้การเข้าถึงแบ็กเอนด์ผ่านโทเค็น ID หลังจากตรวจสอบความถูกต้องและแยกวิเคราะห์การอ้างสิทธิ์แล้ว ไม่ควรส่งการอ้างสิทธิ์ที่กำหนดเองไปยังแบ็กเอนด์โดยตรงเนื่องจากไม่สามารถเชื่อถือได้จากภายนอกโทเค็น

เมื่อการอ้างสิทธิ์ล่าสุดแพร่กระจายไปยังโทเค็น ID ของผู้ใช้คุณสามารถรับได้โดยการเรียกข้อมูลโทเค็น ID:

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();
    }
  }
});

รวดเร็ว

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()
  }
})

วัตถุประสงค์ -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];
    }
  }
}];

แนวทางปฏิบัติที่ดีที่สุดสำหรับการอ้างสิทธิ์ที่กำหนดเอง

การอ้างสิทธิ์ที่กำหนดเองใช้เพื่อให้การควบคุมการเข้าถึงเท่านั้น ไม่ได้ออกแบบมาเพื่อจัดเก็บข้อมูลเพิ่มเติม (เช่นโปรไฟล์และข้อมูลที่กำหนดเองอื่น ๆ ) แม้ว่าวิธีนี้อาจดูเหมือนเป็นกลไกที่สะดวกในการทำเช่นนั้น แต่ก็ไม่ควรอย่างยิ่งเนื่องจากการอ้างสิทธิ์เหล่านี้ถูกเก็บไว้ในโทเค็น ID และอาจทำให้เกิดปัญหาด้านประสิทธิภาพเนื่องจากคำขอที่ตรวจสอบสิทธิ์ทั้งหมดจะมีโทเค็น Firebase ID ที่ตรงกับผู้ใช้ที่ลงชื่อเข้าใช้เสมอ

  • ใช้การอ้างสิทธิ์ที่กำหนดเองเพื่อจัดเก็บข้อมูลสำหรับควบคุมการเข้าถึงของผู้ใช้เท่านั้น ข้อมูลอื่น ๆ ทั้งหมดควรจัดเก็บแยกกันผ่านฐานข้อมูลแบบเรียลไทม์หรือที่เก็บข้อมูลฝั่งเซิร์ฟเวอร์อื่น ๆ
  • การอ้างสิทธิ์ที่กำหนดเองมีขนาด จำกัด การส่งผ่านเพย์โหลดการอ้างสิทธิ์ที่กำหนดเองที่มีขนาดใหญ่กว่า 1,000 ไบต์จะทำให้เกิดข้อผิดพลาด

ตัวอย่างและกรณีการใช้งาน

ตัวอย่างต่อไปนี้แสดงการอ้างสิทธิ์ที่กำหนดเองในบริบทของกรณีการใช้งาน Firebase ที่เฉพาะเจาะจง

การกำหนดบทบาทผ่าน Firebase Functions ในการสร้างผู้ใช้

ในตัวอย่างนี้การอ้างสิทธิ์ที่กำหนดเองถูกตั้งค่าสำหรับผู้ใช้ในการสร้างโดยใช้ Cloud Functions

สามารถเพิ่มการอ้างสิทธิ์ที่กำหนดเองได้โดยใช้ Cloud Functions และเผยแพร่ทันทีด้วย Realtime Database ฟังก์ชันนี้ถูกเรียกใช้เฉพาะเมื่อสมัครใช้งานโดยใช้ทริกเกอร์ onCreate เมื่อตั้งค่าการอ้างสิทธิ์ที่กำหนดเองแล้วการอ้างสิทธิ์ดังกล่าวจะเผยแพร่ไปยังเซสชันที่มีอยู่ทั้งหมดและในอนาคต ในครั้งต่อไปที่ผู้ใช้ลงชื่อเข้าใช้ด้วยข้อมูลรับรองของผู้ใช้โทเค็นจะมีการอ้างสิทธิ์ที่กำหนดเอง

การใช้งานฝั่งไคลเอ็นต์ (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);
  }
});

ตรรกะของ Cloud Functions

มีการเพิ่มโหนดฐานข้อมูลใหม่ (metadata / ($ uid)} ที่มีการอ่าน / เขียน จำกัด เฉพาะผู้ใช้ที่พิสูจน์ตัวตนแล้ว

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);
      });
  }
});

กฎฐานข้อมูล

{
  "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

ตัวอย่างต่อไปนี้ตั้งค่าการอ้างสิทธิ์ของผู้ใช้แบบกำหนดเองสำหรับผู้ใช้ที่เพิ่งลงชื่อเข้าใช้ผ่านคำขอ HTTP

การใช้งานฝั่งไคลเอ็นต์ (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);
});

การใช้งานแบ็กเอนด์ (Admin SDK)

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'});
    }
  });
});

สามารถใช้โฟลว์เดียวกันเมื่ออัปเกรดระดับการเข้าถึงของผู้ใช้ที่มีอยู่ ยกตัวอย่างเช่นผู้ใช้ฟรีอัปเกรดเป็นการสมัครสมาชิกแบบชำระเงิน โทเค็น ID ของผู้ใช้จะถูกส่งพร้อมข้อมูลการชำระเงินไปยังเซิร์ฟเวอร์แบ็กเอนด์ผ่านคำขอ HTTP เมื่อดำเนินการชำระเงินเรียบร้อยแล้วผู้ใช้จะถูกตั้งค่าเป็นสมาชิกแบบชำระเงินผ่าน Admin SDK การตอบกลับ HTTP ที่ประสบความสำเร็จจะถูกส่งกลับไปยังไคลเอนต์เพื่อบังคับให้มีการรีเฟรชโทเค็น

การกำหนดบทบาทผ่านสคริปต์แบ็กเอนด์

สคริปต์ที่เกิดซ้ำ (ไม่ได้เริ่มต้นจากไคลเอนต์) สามารถตั้งค่าให้รันเพื่ออัปเดตการอ้างสิทธิ์ที่กำหนดเองของผู้ใช้:

โหนด 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);
}

Python

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
    })

ไป

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)
	}

}

ค#

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);
}

นอกจากนี้ยังสามารถแก้ไขการอ้างสิทธิ์ที่กำหนดเองได้ทีละน้อยผ่าน Admin SDK:

โหนด 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);
}

Python

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)

ไป

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)
	}

}

ค#

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);
}