Firebase trao cho bạn toàn quyền kiểm soát đối với việc xác thực bằng cách cho phép bạn
xác thực người dùng hoặc thiết bị bằng Mã thông báo web JSON (JWT) bảo mật. Bạn tạo
các mã thông báo này trên máy chủ của bạn, truyền lại về thiết bị khách rồi sử dụng
chúng để xác thực thông qua phương thức signInWithCustomToken()
.
Để làm được việc này, bạn phải tạo một điểm cuối máy chủ chấp nhận hoạt động đăng nhập
thông tin xác thực (chẳng hạn như tên người dùng và mật khẩu) và nếu thông tin đăng nhập
hợp lệ, trả về một JWT tuỳ chỉnh. Sau đó, JWT tuỳ chỉnh được trả về từ máy chủ của bạn có thể
được thiết bị khách sử dụng để xác thực với Firebase
(iOS+, Android,
web). Sau khi được xác thực, danh tính này sẽ
được sử dụng khi truy cập vào các dịch vụ Firebase khác, chẳng hạn như Firebase Realtime Database
và Cloud Storage. Hơn nữa, nội dung của JWT sẽ
có sẵn trong đối tượng auth
trong
Realtime Database Security Rules và
request.auth
trong đối tượng của bạn
Cloud Storage Security Rules.
Bạn có thể tạo mã thông báo tuỳ chỉnh bằng SDK quản trị của Firebase, hoặc bạn có thể sử dụng thư viện JWT của bên thứ ba nếu máy chủ của bạn được viết bằng một ngôn ngữ mà Firebase không hỗ trợ sẵn.
Trước khi bắt đầu
Mã thông báo tuỳ chỉnh được ký JWT, trong đó khoá riêng tư dùng để ký thuộc về tài khoản dịch vụ của Google. Có một số cách để chỉ định dịch vụ của Google tài khoản mà SDK quản trị Firebase sẽ sử dụng để ký mã thông báo:
- Sử dụng tệp JSON của tài khoản dịch vụ -- Phương thức này có thể được sử dụng trong bất kỳ nhưng yêu cầu bạn đóng gói tệp JSON của tài khoản dịch vụ cùng với mã của bạn. Bạn phải đặc biệt chú ý để đảm bảo rằng tệp JSON của tài khoản dịch vụ sẽ không bị lộ cho bên ngoài.
- Cho phép SDK dành cho quản trị viên khám phá một tài khoản dịch vụ -- Phương thức này có thể dùng trong các môi trường do Google quản lý như Google Cloud Hàm và App Engine. Bạn có thể phải định cấu hình một số các quyền bổ sung thông qua bảng điều khiển Google Cloud.
- Sử dụng mã tài khoản dịch vụ – Khi được sử dụng trong môi trường do Google quản lý, phương thức này sẽ ký mã thông báo bằng khoá của tài khoản dịch vụ đã chỉ định. Tuy nhiên, trang này sử dụng dịch vụ web từ xa và bạn có thể phải định cấu hình các quyền bổ sung cho tài khoản dịch vụ này thông qua Bảng điều khiển Google Cloud.
Sử dụng tệp JSON của tài khoản dịch vụ
Các tệp JSON của tài khoản dịch vụ chứa tất cả thông tin tương ứng với dịch vụ tài khoản (bao gồm cả khoá riêng tư RSA). Bạn có thể tải các tệp này xuống từ Bảng điều khiển Firebase. Thực hiện theo quy trình thiết lập SDK dành cho quản trị viên hướng dẫn của chúng tôi để biết thêm thông tin về cách khởi chạy SDK dành cho quản trị viên bằng tệp JSON của tài khoản dịch vụ.
Phương pháp khởi chạy này phù hợp với nhiều SDK dành cho quản trị viên nhiều lần triển khai. Ngoài ra, mã này cho phép SDK dành cho quản trị viên tạo và ký mã thông báo tuỳ chỉnh cục bộ mà không cần thực hiện bất kỳ lệnh gọi API từ xa nào. Nhược điểm chính của phương pháp này là phương pháp yêu cầu bạn đóng gói tệp JSON của tài khoản dịch vụ cùng với mã của bạn. Ngoài ra, xin lưu ý rằng khoá riêng tư trong tài khoản dịch vụ Tệp JSON là thông tin nhạy cảm và bạn phải đặc biệt thận trọng để giữ thông tin đó. Cụ thể, bạn không nên thêm tệp JSON cho tài khoản dịch vụ sang quản lý phiên bản công khai.
Cho phép SDK dành cho quản trị viên khám phá một tài khoản dịch vụ
Nếu bạn triển khai mã trong môi trường do Google quản lý, thì SDK dành cho quản trị viên có thể cố gắng tự động khám phá một phương tiện để ký mã thông báo tuỳ chỉnh:
Nếu bạn triển khai mã trong môi trường tiêu chuẩn App Engine cho Java, Python hoặc Go, SDK dành cho quản trị viên có thể sử dụng Dịch vụ Danh tính ứng dụng xuất hiện trong môi trường đó để ký mã thông báo tuỳ chỉnh. Dịch vụ Danh tính ứng dụng ký dữ liệu bằng tài khoản dịch vụ mà Ứng dụng Google cấp cho ứng dụng của bạn Công cụ.
Nếu bạn triển khai mã trong một số môi trường được quản lý khác (ví dụ: Google Cloud Hàm, Google Compute Engine), SDK dành cho quản trị viên Firebase có thể tự động khám phá chuỗi mã tài khoản dịch vụ từ máy chủ siêu dữ liệu. Sau đó, mã tài khoản dịch vụ được phát hiện sẽ được dùng cùng với IAM để ký mã thông báo từ xa.
Để sử dụng các phương thức ký này, hãy khởi chạy SDK bằng Google Thông tin xác thực mặc định của ứng dụng và không chỉ định chuỗi mã tài khoản dịch vụ:
Node.js
initializeApp();
Java
FirebaseApp.initializeApp();
Python
default_app = firebase_admin.initialize_app()
Tiến hành
app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
log.Fatalf("error initializing app: %v\n", err)
}
C#
FirebaseApp.Create();
Để kiểm tra cục bộ cùng một mã, hãy tải tệp JSON của tài khoản dịch vụ xuống rồi đặt
biến môi trường GOOGLE_APPLICATION_CREDENTIALS
để trỏ đến biến đó.
Nếu SDK quản trị Firebase phải khám phá một chuỗi mã tài khoản dịch vụ, thì SDK đó sẽ để khi mã của bạn tạo mã thông báo tuỳ chỉnh lần đầu tiên. Kết quả này sẽ được lưu vào bộ nhớ đệm và sử dụng lại cho các hoạt động ký mã thông báo tiếp theo. Mã tài khoản dịch vụ được tự động phát hiện thường là một trong những dịch vụ mặc định tài khoản do Google Cloud cung cấp:
Cũng giống như mã tài khoản dịch vụ được chỉ định rõ ràng, dịch vụ được tự động phát hiện
các mã tài khoản phải có quyền iam.serviceAccounts.signBlob
đối với
có thể tạo mã thông báo tuỳ chỉnh. Bạn có thể phải sử dụng
Phần IAM và quản trị viên
của bảng điều khiển Google Cloud để cấp cho các tài khoản dịch vụ mặc định
các quyền cần thiết. Hãy xem phần khắc phục sự cố bên dưới để biết thêm chi tiết.
Sử dụng mã tài khoản dịch vụ
Để duy trì tính nhất quán giữa các phần khác nhau trong ứng dụng, bạn có thể chỉ định một mã tài khoản dịch vụ có các khoá sẽ được dùng để ký các mã thông báo khi chạy trong môi trường do Google quản lý. Việc này giúp các chính sách IAM trở nên đơn giản và an toàn hơn, đồng thời tránh phải đưa tệp JSON của tài khoản dịch vụ vào mã của bạn.
Bạn có thể tìm thấy mã tài khoản dịch vụ trong
Bảng điều khiển Google Cloud,
hoặc trong trường client_email
của tệp JSON của tài khoản dịch vụ đã tải xuống.
Mã tài khoản dịch vụ là những địa chỉ email có định dạng như sau:
<client-id>@<project-id>.iam.gserviceaccount.com
. Chúng xác định danh tính riêng biệt
tài khoản dịch vụ trong Firebase và dự án Google Cloud.
Để tạo mã thông báo tuỳ chỉnh bằng mã tài khoản dịch vụ riêng, hãy khởi chạy SDK như minh hoạ dưới đây:
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)
Tiến hành
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",
});
Mã tài khoản dịch vụ không phải là thông tin nhạy cảm, do đó khiến thông tin đó bị tiết lộ
là không quan trọng. Tuy nhiên, để ký mã thông báo tuỳ chỉnh bằng dịch vụ đã chỉ định
thì SDK dành cho quản trị viên Firebase phải gọi một dịch vụ từ xa.
Ngoài ra, bạn cũng phải đảm bảo rằng tài khoản dịch vụ mà SDK dành cho quản trị viên
đang dùng để thực hiện cuộc gọi này
—thường là {project-name}@appspot.gserviceaccount.com
—
có iam.serviceAccounts.signBlob
quyền.
Hãy xem phần khắc phục sự cố bên dưới để biết thêm chi tiết.
Tạo mã thông báo tuỳ chỉnh bằng SDK quản trị của Firebase
SDK quản trị của Firebase có phương thức tích hợp để tạo mã thông báo tuỳ chỉnh. Tại
tối thiểu, bạn cần cung cấp uid
, có thể là chuỗi bất kỳ nhưng phải
xác định danh tính chính xác của người dùng hoặc thiết bị mà bạn đang xác thực. Các mã thông báo này sẽ hết hạn
sau một giờ.
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)
Tiến hành
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
Bạn cũng có thể tùy ý chỉ định các xác nhận quyền sở hữu bổ sung để đưa vào tùy chỉnh
mã thông báo. Ví dụ: bên dưới, trường premiumAccount
đã được thêm vào
mã thông báo tuỳ chỉnh. Những mã này sẽ có trong các đối tượng auth
/ request.auth
trong Quy tắc bảo mật của bạn:
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)
Tiến hành
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
Tên dành riêng cho mã thông báo tuỳ chỉnh
Đăng nhập bằng mã thông báo tuỳ chỉnh trên ứng dụng
Sau khi tạo mã thông báo tuỳ chỉnh, bạn nên gửi mã đó đến ứng dụng khách của mình. Chiến lược phát hành đĩa đơn
ứng dụng khách xác thực bằng mã thông báo tuỳ chỉnh bằng cách gọi
signInWithCustomToken()
:
iOS trở lên
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;
// ...
});
Nếu xác thực thành công, người dùng của bạn sẽ được đăng nhập vào
ứng dụng khách với tài khoản do uid
chỉ định trong
mã thông báo. Nếu tài khoản đó trước đây không tồn tại, bản ghi cho người dùng đó sẽ được
đã tạo.
Tương tự như với các phương thức đăng nhập khác (chẳng hạn như
signInWithEmailAndPassword()
và signInWithCredential()
) đối tượng auth
trong Realtime Database Security Rules của bạn và
đối tượng request.auth
trong
Cloud Storage Security Rules sẽ là
được điền sẵn bằng uid
của người dùng. Trong trường hợp này, uid
sẽ là mã mà
mà bạn chỉ định khi tạo mã thông báo tuỳ chỉnh.
Quy tắc về cơ sở dữ liệu
{
"rules": {
"adminContent": {
".read": "auth.uid === 'some-uid'"
}
}
}
Quy tắc lưu trữ
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";
}
}
}
Nếu mã thông báo tuỳ chỉnh có chứa các thông báo xác nhận quyền sở hữu khác, thì bạn có thể tham chiếu những thông báo này
auth.token
(Firebase Realtime Database) hoặc request.auth.token
(Cloud Storage) trong quy tắc của bạn:
Quy tắc về cơ sở dữ liệu
{
"rules": {
"premiumContent": {
".read": "auth.token.premiumAccount === true"
}
}
}
Quy tắc lưu trữ
service firebase.storage {
match /b/<your-firebase-storage-bucket>/o {
match /premiumContent/{filename} {
allow read, write: if request.auth.token.premiumAccount == true;
}
}
}
Tạo mã thông báo tuỳ chỉnh bằng thư viện JWT của bên thứ ba
Nếu chương trình phụ trợ của bạn bằng ngôn ngữ không có Quản trị viên Firebase chính thức SDK, bạn vẫn có thể tạo mã thông báo tuỳ chỉnh theo cách thủ công. Đầu tiên, tìm thư viện JWT của bên thứ ba cho ngôn ngữ của bạn. Sau đó, hãy sử dụng thư viện JWT đó để đúc JWT bao gồm các yêu cầu sau:
Thông báo xác nhận quyền sở hữu mã thông báo tuỳ chỉnh | ||
---|---|---|
alg |
Thuật toán | "RS256" |
iss |
Tổ chức phát hành | Địa chỉ email tài khoản dịch vụ của dự án của bạn |
sub |
Chủ đề | Địa chỉ email tài khoản dịch vụ của dự án của bạn |
aud |
Đối tượng | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat |
Được phát hành tại thời điểm | Thời gian hiện tại, tính bằng giây kể từ thời gian bắt đầu của hệ thống UNIX |
exp |
Thời gian hết hạn |
Khoảng thời gian (tính bằng giây) kể từ thời gian bắt đầu của hệ thống UNIX mà mã thông báo hết hạn. Nó
có thể sớm hơn tối đa 3600 giây so với iat .
Lưu ý: hành động này chỉ kiểm soát thời điểm mà chính mã thông báo tuỳ chỉnh đó hết hạn. Nhưng sau khi bạn đăng nhập người dùng bằng signInWithCustomToken() , họ sẽ vẫn duy trì trạng thái đăng nhập vào
cho đến khi phiên hoạt động của họ không hợp lệ hoặc người dùng đăng xuất.
|
uid |
Giá trị nhận dạng duy nhất của người dùng đã đăng nhập phải là một chuỗi, giữa
Dài từ 1 đến 128 ký tự. uid ngắn hơn có chất lượng tốt hơn
hiệu suất.
|
|
claims (không bắt buộc) |
Thông báo xác nhận quyền sở hữu tuỳ chỉnh không bắt buộc có trong Quy tắc bảo mật auth /
request.auth biến
|
Dưới đây là một số ví dụ về cách triển khai cách tạo mã thông báo tuỳ chỉnh trong nhiều ngôn ngữ mà SDK quản trị Firebase không hỗ trợ:
PHP
Sử dụng 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
Sử dụng 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
Sau khi bạn tạo mã thông báo tuỳ chỉnh, hãy gửi mã đó đến ứng dụng khách để sử dụng xác thực bằng Firebase. Hãy xem các mã mẫu ở trên để biết cách thực hiện việc này.
Khắc phục sự cố
Phần này trình bày một số vấn đề phổ biến mà nhà phát triển có thể gặp phải khi tạo mã thông báo tuỳ chỉnh và cách giải quyết mã đó.
Chưa bật IAM API
Nếu đang chỉ định mã tài khoản dịch vụ để ký mã thông báo, bạn có thể nhận được một lỗi tương tự như sau:
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.
SDK quản trị của Firebase sử dụng API IAM để ký mã thông báo. Lỗi này cho biết API IAM hiện chưa được bật cho Dự án Firebase. Mở đường liên kết trong thông báo lỗi trên một trình duyệt web rồi hãy nhấp vào nút "Bật API" để bật tính năng này cho dự án của bạn.
Tài khoản dịch vụ không có các quyền cần thiết
Nếu tài khoản dịch vụ mà SDK quản trị Firebase đang chạy vì không có
iam.serviceAccounts.signBlob
, bạn có thể nhận được thông báo lỗi như
như sau:
Permission iam.serviceAccounts.signBlob is required to perform this operation on service account projects/-/serviceAccounts/{your-service-account-id}.
Cách dễ nhất để giải quyết vấn đề này là cấp cho "Người tạo mã thông báo tài khoản dịch vụ"
vai trò IAM đối với tài khoản dịch vụ có liên quan, thường là
{project-name}@appspot.gserviceaccount.com
:
- Mở IAM và quản trị viên trong bảng điều khiển Google Cloud.
- Chọn dự án của bạn rồi nhấp vào "Tiếp tục".
- Nhấp vào biểu tượng chỉnh sửa tương ứng với tài khoản dịch vụ mà bạn muốn cập nhật.
- Nhấp vào "Thêm vai trò khác".
- Nhập "Người tạo mã thông báo tài khoản dịch vụ" vào bộ lọc tìm kiếm rồi chọn nội dung đó khỏi kết quả.
- Nhấp vào "Lưu" để xác nhận việc cấp vai trò.
Tham khảo tài liệu về quản lý danh tính và quyền truy cập (IAM) để biết thêm chi tiết về quy trình này hoặc tìm hiểu cách cập nhật vai trò bằng cách sử dụng gcloud.
Không xác định được tài khoản dịch vụ
Nếu bạn nhận được thông báo lỗi tương tự như sau, thì SDK Quản trị Firebase chưa được khởi chạy đúng cách.
Failed to determine service account ID. Initialize the SDK with service account credentials or specify a service account ID with iam.serviceAccounts.signBlob permission.
Nếu bạn đang dựa vào SDK để tự động khám phá mã tài khoản dịch vụ, hãy đảm bảo mã được triển khai trong môi trường được quản lý của Google bằng máy chủ siêu dữ liệu. Nếu không, hãy nhớ chỉ định tệp JSON của tài khoản dịch vụ hoặc mã tài khoản dịch vụ lúc khởi chạy SDK.