Gerir inquilinos da Identity Platform através de programação
Este documento explica como usar o SDK de administrador da Identity Platform para gerir inquilinos e os respetivos utilizadores de forma programática. Seguem-se algumas atividades que pode realizar como administrador:
Gestão de utilizadores: crie, atualize, elimine e liste utilizadores para um inquilino específico.
Validação de identidade: identifique os utilizadores de uma app para restringir o acesso a recursos no seu próprio servidor.
Importar utilizadores: migre utilizadores de um sistema de autenticação externo ou de outro projeto ou inquilino da Identity Platform.
Controlo de acesso com reivindicações personalizadas: defina atributos personalizados em contas de utilizador para um inquilino específico e implemente várias estratégias de controlo de acesso, como o controlo de acesso baseado em funções.
Gestão de sessões de utilizadores: revogue os tokens de atualização de um utilizador para um inquilino específico.
Links de ações por email: gere links de email personalizados para a reposição de palavras-passe, o início de sessão por link de email e a validação de email para utilizadores de um inquilino específico.
Gestão de inquilinos: crie, liste, obtenha, atualize e elimine inquilinos para um projeto específico do Identity Platform.
Faça a gestão de fornecedores OIDC e SAML em inquilinos: faça a gestão programática de configurações OIDC e SAML num inquilino especificado.
Antes de começar
Instale o SDK Admin para Node.js, Java, Python, Go ou C#.
Ative a multilocação para o seu Google Cloud projeto.
Funcionalidades suportadas
A tabela seguinte indica as funcionalidades suportadas por cada SDK num ambiente multiinquilino:
Funcionalidade | Node.js | Java | Python | Ir | C# |
---|---|---|---|---|---|
Criação de tokens personalizados | |||||
Validar tokens de ID | |||||
Gerir utilizadores | |||||
Controlar o acesso com reivindicações personalizadas | |||||
Revogar tokens de atualização | |||||
A importar utilizadores | |||||
Gerar links de ação de email | |||||
Autenticação multifator | |||||
Gerir configurações de fornecedores SAML/OIDC | |||||
Gestão de cookies de sessão |
A tabela seguinte mostra os métodos de início de sessão que pode configurar através do Admin SDK e da Google Cloud consola num contexto específico do inquilino:
Funcionalidade | Google Cloud consola | SDK de administrador |
---|---|---|
OIDC | ||
SAML | ||
Redes sociais | ||
Telefone | ||
Autenticação multifator | ||
Anónimo |
Gestão de inquilinos
Através do SDK de administrador, pode gerir inquilinos programaticamente a partir de um ambiente de servidor seguro em vez de usar a Google Cloud consola. Isto inclui a capacidade de criar, listar, obter, modificar ou eliminar inquilinos.
Cada inquilino contém os seus próprios fornecedores de identidade, definições e conjuntos de utilizadores.
As operações de gestão da configuração do inquilino (CRUD) estão disponíveis a partir da instância do projeto principal através da API admin.auth().tenantManager()
.
Uma configuração de inquilino fornece informações sobre um inquilino, como o respetivo nome a apresentar, identificador de inquilino e configuração de autenticação de email.
Todas as outras definições (como domínios na lista de autorizações e URIs de redirecionamento autenticados) de um inquilino são herdadas do projeto principal. Têm de ser geridas através da Google Cloud consola.
Para operações como a gestão de utilizadores específica do inquilino, a configuração de fornecedores OIDC/SAML e a geração de links de email, precisa de uma instância TenantAwareAuth
para o inquilino de destino (identificado pelo respetivo tenantId
exclusivo).
Node.js
const tenantManager = admin.auth().tenantManager();
const tenantAuth = tenantManager.authForTenant(tenantId);
Python
from firebase_admin import tenant_mgt tenant_client = tenant_mgt.auth_for_tenant(tenant_id)
Java
FirebaseAuth auth = FirebaseAuth.getInstance(); TenantManager tenantManager = auth.getTenantManager(); TenantAwareFirebaseAuth tenantAuth = tenantManager.getAuthForTenant(tenantId);
Todas as chamadas para as APIs de gestão de utilizadores, as APIs de gestão de fornecedores OIDC/SAML e as APIs de geração de links de email estarão no âmbito deste inquilino (através da respetiva instância TenantAwareAuth
).
Obter um inquilino existente
O SDK de administração fornece o método getTenant()
, que obtém informações
acerca de um inquilino com base no respetivo tenantId
(um identificador exclusivo do inquilino).
Node.js
admin.auth().tenantManager().getTenant(tenantId)
.then((tenant) => {
console.log(tenant.toJSON());
})
.catch((error) => {
// Handle error.
});
Python
tenant = tenant_mgt.get_tenant(tenant_id) print('Retreieved tenant:', tenant.tenant_id)
Java
Tenant tenant = FirebaseAuth.getInstance().getTenantManager().getTenant(tenantId); System.out.println("Retrieved tenant: " + tenant.getTenantId());
Este método devolve um objeto Tenant
correspondente ao tenantId
.
Se o tenantId
fornecido não pertencer a um inquilino existente, a promessa devolvida é rejeitada com um erro auth/tenant-not-found
.
Tenha cuidado para não confundir uma instância Tenant
com um objeto TenantAwareAuth
. authInstance.tenantManager().authForTenant()
devolve uma instância de TenantAwareAuth
que se estende a BaseAuth
.
A Auth
aula também se estende BaseAuth
.
BaseAuth
fornece APIs para gerir utilizadores e configurar fornecedores OIDC/SAML em diferentes contextos. Para Auth
, o contexto está ao nível do projeto principal.
Para TenantAwareAuth
, o contexto está ao nível do inquilino (o inquilino é determinado pelo ID do inquilino). O método getTenant()
é resolvido com informações básicas do inquilino (como o ID do inquilino, o nome a apresentar e as definições do fornecedor de email), mas, para chamar APIs nesse inquilino, tem de usar authForTenant(tenantFromGetTenant.tenantId)
.
Criar um inquilino
Use o método createTenant()
para criar uma nova configuração de inquilino:
Node.js
admin.auth().tenantManager().createTenant({
displayName: 'myTenant1',
emailSignInConfig: {
enabled: true,
passwordRequired: false, // Email link sign-in enabled.
},
// TODO: Remove if you don't want to enable multi-factor authentication.
multiFactorConfig: {
state: 'ENABLED',
factorIds: ['phone']
},
// TODO: Remove if you don't want to register test phone numbers for use
// with multi-factor authentication.
testPhoneNumbers: {
'+16505551234': '145678',
'+16505550000': '123456'
},
})
.then((createdTenant) => {
console.log(createdTenant.toJSON());
})
.catch((error) => {
// Handle error.
});
Python
tenant = tenant_mgt.create_tenant( display_name='myTenant1', enable_email_link_sign_in=True, allow_password_sign_up=True) print('Created tenant:', tenant.tenant_id)
Java
Tenant.CreateRequest request = new Tenant.CreateRequest() .setDisplayName("myTenant1") .setEmailLinkSignInEnabled(true) .setPasswordSignInAllowed(true); Tenant tenant = FirebaseAuth.getInstance().getTenantManager().createTenant(request); System.out.println("Created tenant: " + tenant.getTenantId());
Pode fornecer qualquer combinação destas propriedades:
Propriedade | Tipo | Descrição |
---|---|---|
displayName |
string |
O nome a apresentar do inquilino. Tem de ter entre 4 e 20 carateres, consistir em letras, dígitos e hífenes, e começar por uma letra. |
emailSignInConfig |
{ enable: boolean, passwordRequired: boolean } |
A configuração do fornecedor de início de sessão por email. Isto inclui se o fornecedor de email está ativado e se é necessária uma palavra-passe para iniciar sessão por email. Quando não é obrigatório, o início de sessão por email pode ser feito com uma palavra-passe ou através do início de sessão por link de email. |
multiFactorConfig |
{ state: 'DISABLED' | 'ENABLED', factorIds: string[] } |
Se a autenticação multifator está ativada para o inquilino e que tipos de fatores são permitidos. Atualmente, o único ID do fator suportado é phone .
|
testPhoneNumbers |
{ string: string } |
Um mapa de números de telefone e os respetivos códigos de autenticação multifator associados para registo
para fins de teste.
São permitidas, no máximo, 10 entradas. Para remover todos os números de telefone de teste, defina este campo como null .
|
O método devolve um objeto Tenant
para o inquilino criado recentemente.
Atualizar um inquilino
Use o método updateTenant()
para modificar os dados de um inquilino existente. Tem de especificar o tenantId
, juntamente com as propriedades a atualizar para esse inquilino.
Node.js
admin.auth().tenantManager().updateTenant(tenantId, {
displayName: 'updatedName',
emailSignInConfig: {
enabled: false, // Disable email provider.
},
// Enable multi-factor authentication.
multiFactorConfig: {
state: 'ENABLED',
factorIds: ['phone']
},
// Register phone numbers for testing.
testPhoneNumbers: {
'+16505551234': '145678',
'+16505550000': '123456'
},
})
.then((updatedTenant) => {
console.log(updatedTenant.toJSON());
})
.catch((error) => {
// Handle error.
});
Python
tenant = tenant_mgt.update_tenant( tenant_id, display_name='updatedName', allow_password_sign_up=False) # Disable email provider print('Updated tenant:', tenant.tenant_id)
Java
Tenant.UpdateRequest request = new Tenant.UpdateRequest(tenantId) .setDisplayName("updatedName") .setPasswordSignInAllowed(false); Tenant tenant = FirebaseAuth.getInstance().getTenantManager().updateTenant(request); System.out.println("Updated tenant: " + tenant.getTenantId());
updateTenant()
aceita as mesmas propriedades que createTenant()
. Todas as propriedades
são opcionais. Se uma propriedade não for especificada, o valor existente não é
modificado.
O método devolve um objeto Tenant
atualizado após a conclusão. Se o tenantId
fornecido não pertencer a um inquilino existente, a promessa devolvida é rejeitada com um erro auth/tenant-not-found
.
Eliminar um inquilino
Pode eliminar um inquilino através do respetivo tenantId
:
Node.js
admin.auth().tenantManager().deleteTenant(tenantId)
.then(() => {
// Tenant deleted.
})
.catch((error) => {
// Handle error.
});
Python
tenant_mgt.delete_tenant(tenant_id)
Java
FirebaseAuth.getInstance().getTenantManager().deleteTenant(tenantId);
O método devolve um resultado vazio quando a eliminação é concluída com êxito.
Se o tenantId
fornecido não pertencer a um inquilino existente, a promessa devolvida é rejeitada com um erro auth/tenant-not-found
.
Inquilinos de fichas
Use o método listTenants()
para listar os inquilinos existentes:
Node.js
function listAllTenants(nextPageToken) {
return admin.auth().tenantManager().listTenants(100, nextPageToken)
.then((result) => {
result.tenants.forEach((tenant) => {
console.log(tenant.toJSON());
});
if (result.pageToken) {
return listAllTenants(result.pageToken);
}
});
}
listAllTenants();
Python
for tenant in tenant_mgt.list_tenants().iterate_all(): print('Retrieved tenant:', tenant.tenant_id)
Java
ListTenantsPage page = FirebaseAuth.getInstance().getTenantManager().listTenants(null); for (Tenant tenant : page.iterateAll()) { System.out.println("Retrieved tenant: " + tenant.getTenantId()); }
Cada lote de resultados contém uma lista de inquilinos, além de um token de página seguinte para listar o lote seguinte de inquilinos. Quando todos os inquilinos já foram listados, não é devolvido nenhum pageToken
.
Se não for especificado nenhum campo maxResults
, a predefinição é de 1000 inquilinos por lote.
Este é também o número máximo de inquilinos que podem ser apresentados em simultâneo.
Qualquer valor superior ao máximo gera um erro de argumento.
Se não for especificado nenhum pageToken
, o método apresenta uma lista de inquilinos desde o início.
Gerir fornecedores SAML e OIDC de forma programática
O SDK de administrador fornece APIs para gerir programaticamente as configurações do fornecedor de linguagem de marcação de declarações de segurança (SAML) 2.0 e OpenID Connect (OIDC) a partir de um ambiente de servidor seguro.
Com o SDK Admin, pode gerir estes fornecedores para um inquilino específico. Isto é semelhante à gestão de fornecedores OIDC e SAML ao nível do projeto.
Para gerir fornecedores para um inquilino, crie primeiro uma instância TenantAwareAuth
:
Node.js
const tenantAuth = admin.auth().tenantManager().authForTenant('TENANT-ID');
Python
tenant_client = tenant_mgt.auth_for_tenant('TENANT-ID')
Java
TenantAwareFirebaseAuth tenantAuth = FirebaseAuth.getInstance().getTenantManager() .getAuthForTenant("TENANT-ID");
Em seguida, pode realizar operações comuns, como criar, modificar ou eliminar fornecedores para um inquilino.
Criar um fornecedor
O código seguinte mostra como criar um fornecedor SAML para um inquilino:
Node.js
const newConfig = {
displayName: 'SAML provider name',
enabled: true,
providerId: 'saml.myProvider',
idpEntityId: 'IDP_ENTITY_ID',
ssoURL: 'https://example.com/saml/sso/1234/',
x509Certificates: [
'-----BEGIN CERTIFICATE-----\nCERT1...\n-----END CERTIFICATE-----',
'-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----'
],
rpEntityId: 'RP_ENTITY_ID',
// Using the default callback URL.
callbackURL: 'https://project-id.firebaseapp.com/__/auth/handler'
};
tenantAuth.createProviderConfig(newConfig).then(() => {
// Successful creation.
}).catch((error) => {
// Handle error.
});
Python
saml = tenant_client.create_saml_provider_config( display_name='SAML provider name', enabled=True, provider_id='saml.myProvider', idp_entity_id='IDP_ENTITY_ID', sso_url='https://example.com/saml/sso/1234/', x509_certificates=[ '-----BEGIN CERTIFICATE-----\nCERT1...\n-----END CERTIFICATE-----', '-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----', ], rp_entity_id='P_ENTITY_ID', callback_url='https://project-id.firebaseapp.com/__/auth/handler') print('Created new SAML provider:', saml.provider_id)
Java
SamlProviderConfig.CreateRequest request = new SamlProviderConfig.CreateRequest() .setDisplayName("SAML provider name") .setEnabled(true) .setProviderId("saml.myProvider") .setIdpEntityId("IDP_ENTITY_ID") .setSsoUrl("https://example.com/saml/sso/1234/") .addX509Certificate("-----BEGIN CERTIFICATE-----\nCERT1...\n-----END CERTIFICATE-----") .addX509Certificate("-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----") .setRpEntityId("RP_ENTITY_ID") .setCallbackUrl("https://project-id.firebaseapp.com/__/auth/handler"); SamlProviderConfig saml = tenantAuth.createSamlProviderConfig(request); System.out.println("Created new SAML provider: " + saml.getProviderId());
Modificar um fornecedor
O código seguinte mostra como modificar um fornecedor:
Node.js
const updatedConfig = {
x509Certificates: [
'-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----',
'-----BEGIN CERTIFICATE-----\nCERT3...\n-----END CERTIFICATE-----',
],
};
tenantAuth.updateProviderConfig('saml.myProvider', updatedConfig).then(() => {
// Successful update.
}).catch((error) => {
// Handle error.
});
Python
saml = tenant_client.update_saml_provider_config( 'saml.myProvider', x509_certificates=[ '-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----', '-----BEGIN CERTIFICATE-----\nCERT3...\n-----END CERTIFICATE-----', ]) print('Updated SAML provider:', saml.provider_id)
Java
SamlProviderConfig.UpdateRequest request = new SamlProviderConfig.UpdateRequest("saml.myProvider") .addX509Certificate("-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----") .addX509Certificate("-----BEGIN CERTIFICATE-----\nCERT3...\n-----END CERTIFICATE-----"); SamlProviderConfig saml = tenantAuth.updateSamlProviderConfig(request); System.out.println("Updated SAML provider: " + saml.getProviderId());
Obter um fornecedor
O código seguinte mostra como obter a configuração do fornecedor para um inquilino específico através do respetivo ID do fornecedor:
Node.js
tenantAuth.getProviderConfig('saml.myProvider').then((config) => {
// Get display name and whether it is enabled.
console.log(config.displayName, config.enabled);
}).catch((error) => {
// Handle error. Common error is that config is not found.
});
Python
saml = tennat_client.get_saml_provider_config('saml.myProvider') print(saml.display_name, saml.enabled)
Java
SamlProviderConfig saml = tenantAuth.getSamlProviderConfig("saml.myProvider"); // Get display name and whether it is enabled. System.out.println(saml.getDisplayName() + " " + saml.isEnabled());
Fornecedores de fichas
O código seguinte mostra como listar as configurações de fornecedores para um determinado inquilino:
Node.js
// Returns 10 SAML provider configs starting from the specified nextPageToken offset.
tenantAuth.listProviderConfigs({type: 'saml', maxResults: 10, pageToken: 'nextPageToken'}).then((results) => {
results.providerConfigs.forEach((config) => {
console.log(config.providerId);
});
// To list the next 10:
// return tenantAuth.listProviderConfigs(
// {type: 'saml', maxResults: 10, pageToken: results.pageToken});
}).catch((error) => {
// Handle error.
});
Python
for saml in tenant_client.list_saml_provider_configs('nextPageToken').iterate_all(): print(saml.provider_id)
Java
ListProviderConfigsPage<SamlProviderConfig> page = tenantAuth.listSamlProviderConfigs( "nextPageToken"); for (SamlProviderConfig saml : page.iterateAll()) { System.out.println(saml.getProviderId()); }
Eliminar um fornecedor
O código seguinte mostra como eliminar um fornecedor:
Node.js
tenantAuth.deleteProviderConfig('saml.myProvider').then(() => {
// Successful deletion.
}).catch((error) => {
// Handle error.
});
Python
tenant_client.delete_saml_provider_config('saml.myProvider')
Java
tenantAuth.deleteSamlProviderConfig("saml.myProvider");
Os fornecedores OIDC são geridos de forma semelhante aos fornecedores OIDC ao nível do projeto, exceto que
podem ser geridos a partir da instância TenantAwareAuth
correspondente, em vez
de uma instância ao nível do projeto Auth
.
Para saber mais, consulte o artigo Gerir fornecedores SAML e OIDC através de programação.
Gerir utilizadores específicos do inquilino
Pode usar o SDK de administrador para criar, obter, atualizar, eliminar e listar todos os utilizadores de um inquilino específico.
Para começar, precisa de uma instância do TenantAwareAuth
para o inquilino correspondente:
Node.js
const tenantAuth = admin.auth().tenantManager().authForTenant('TENANT-ID');
Python
tenant_client = tenant_mgt.auth_for_tenant('TENANT-ID')
Java
TenantAwareFirebaseAuth tenantAuth = FirebaseAuth.getInstance().getTenantManager() .getAuthForTenant("TENANT-ID");
Obter um utilizador
Pode obter um utilizador específico do inquilino com um identificador uid
:
Node.js
tenantAuth.getUser(uid)
.then((userRecord) => {
// See the UserRecord reference documentation to learn more.
console.log('Successfully fetched user data:', userRecord.toJSON());
// Tenant ID will be reflected in userRecord.tenantId.
})
.catch((error) => {
console.log('Error fetching user data:', error);
});
Python
# Get an auth.Client from tenant_mgt.auth_for_tenant() user = tenant_client.get_user(uid) print('Successfully fetched user data:', user.uid)
Java
// Get an auth client from the firebase.App UserRecord user = tenantAuth.getUser(uid); System.out.println("Successfully fetched user data: " + user.getDisplayName());
Também pode identificar um utilizador pelo respetivo email:
Node.js
tenantAuth.getUserByEmail(email)
.then((userRecord) => {
// See the UserRecord reference documentation to learn more.
console.log('Successfully fetched user data:', userRecord.toJSON());
// Tenant ID will be reflected in userRecord.tenantId.
})
.catch((error) => {
console.log('Error fetching user data:', error);
});
Python
user = tenant_client.get_user_by_email(email) print('Successfully fetched user data:', user.uid)
Java
// Get an auth client from the firebase.App UserRecord user = tenantAuth.getUserByEmail(email); System.out.println("Successfully fetched user data: " + user.getDisplayName());
A criar um utilizador
Use o método createUser()
para criar novos utilizadores para um inquilino específico.
Ao criar um novo utilizador, fornecer um uid
é opcional. Se não for especificado, a Identity Platform vai aprovisionar um exclusivo.
Node.js
tenantAuth.createUser({
email: 'user@example.com',
emailVerified: false,
phoneNumber: '+11234567890',
password: 'secretPassword',
displayName: 'John Doe',
photoURL: 'http://www.example.com/12345678/photo.png',
disabled: false
})
.then((userRecord) => {
// See the UserRecord reference documentation to learn more.
console.log('Successfully created new user:', userRecord.uid);
// Tenant ID will be reflected in userRecord.tenantId.
})
.catch((error) => {
console.log('Error creating new user:', error);
});
Python
user = tenant_client.create_user( email='user@example.com', email_verified=False, phone_number='+15555550100', password='secretPassword', display_name='John Doe', photo_url='http://www.example.com/12345678/photo.png', disabled=False) print('Sucessfully created new user:', user.uid)
Java
UserRecord.CreateRequest request = new UserRecord.CreateRequest() .setEmail("user@example.com") .setEmailVerified(false) .setPhoneNumber("+15555550100") .setPassword("secretPassword") .setDisplayName("John Doe") .setPhotoUrl("http://www.example.com/12345678/photo.png") .setDisabled(false); UserRecord user = tenantAuth.createUser(request); System.out.println("Successfully created user: " + user.getDisplayName());
Modificar um utilizador
Pode modificar os utilizadores existentes especificando o respetivo uid
no método updateUser()
:
Node.js
tenantAuth.updateUser(uid, {
email: 'modifiedUser@example.com',
phoneNumber: '+11234567890',
emailVerified: true,
password: 'newPassword',
displayName: 'Jane Doe',
photoURL: 'http://www.example.com/12345678/photo.png',
disabled: true
})
.then((userRecord) => {
// See the UserRecord reference documentation to learn more.
console.log('Successfully updated user', userRecord.toJSON());
})
.catch((error) => {
console.log('Error updating user:', error);
});
Python
user = tenant_client.update_user( uid, email='user@example.com', phone_number='+15555550100', email_verified=True, password='newPassword', display_name='John Doe', photo_url='http://www.example.com/12345678/photo.png', disabled=True) print('Sucessfully updated user:', user.uid)
Java
UserRecord.UpdateRequest request = new UserRecord.UpdateRequest(uid) .setEmail("user@example.com") .setEmailVerified(true) .setPhoneNumber("+15555550100") .setPassword("newPassword") .setDisplayName("John Doe") .setPhotoUrl("http://www.example.com/12345678/photo.png") .setDisabled(true); UserRecord user = tenantAuth.updateUser(request); System.out.println("Successfully updated user: " + user.getDisplayName());
Eliminar um utilizador
O exemplo seguinte mostra como eliminar um utilizador com base no respetivo uid
:
Node.js
tenantAuth.deleteUser(uid)
.then(() => {
console.log('Successfully deleted user');
})
.catch((error) => {
console.log('Error deleting user:', error);
});
Python
tenant_client.delete_user(uid) print('Successfully deleted user')
Java
tenantAuth.deleteUser(uid); System.out.println("Successfully deleted user: " + uid);
Listar utilizadores
Para obter uma lista completa de utilizadores de um inquilino específico em lotes, use o método listUsers()
. Cada lote contém uma lista de registos de utilizadores, além de um token de página seguinte se existirem utilizadores adicionais.
Node.js
function listAllUsers(nextPageToken) {
// List batch of users, 1000 at a time.
tenantAuth.listUsers(1000, nextPageToken)
.then((listUsersResult) => {
listUsersResult.users.forEach((userRecord) => {
console.log('user', userRecord.toJSON());
// Tenant ID will be reflected in userRecord.tenantId.
});
if (listUsersResult.pageToken) {
// List next batch of users.
listAllUsers(listUsersResult.pageToken);
}
})
.catch((error) => {
console.log('Error listing users:', error);
});
}
// Start listing users from the beginning, 1000 at a time.
listAllUsers();
Python
# Note, behind the scenes, the iterator will retrive 1000 users at a time through the API for user in tenant_client.list_users().iterate_all(): print('User: ' + user.uid) # Iterating by pages of 1000 users at a time. page = tenant_client.list_users() while page: for user in page.users: print('User: ' + user.uid) # Get next batch of users. page = page.get_next_page()
Java
// Note, behind the scenes, the ListUsersPage retrieves 1000 Users at a time // through the API ListUsersPage page = tenantAuth.listUsers(null); for (ExportedUserRecord user : page.iterateAll()) { System.out.println("User: " + user.getUid()); } // Iterating by pages 100 users at a time. page = tenantAuth.listUsers(null, 100); while (page != null) { for (ExportedUserRecord user : page.getValues()) { System.out.println("User: " + user.getUid()); } page = page.getNextPage(); }
Consulte a documentação do SDK de administrador sobre como gerir utilizadores para saber mais.
A importar utilizadores
Pode usar o SDK de administrador para importar utilizadores em massa para um inquilino específico com privilégios elevados. Isto oferece várias vantagens, como a capacidade de migrar utilizadores de outro produto da Identity Platform, de outro inquilino ou de um sistema de autenticação externo através de um algoritmo de hash diferente. Também pode importar utilizadores com fornecedores federados (como SAML e OIDC) e reivindicações personalizadas diretamente em massa.
Para começar, obtenha uma instância TenantAwareAuth
para o inquilino correspondente:
Node.js
const tenantAuth = admin.auth().tenantManager().authForTenant('TENANT-ID');
Python
tenant_client = tenant_mgt.auth_for_tenant('TENANT-ID')
Java
TenantAwareFirebaseAuth tenantAuth = FirebaseAuth.getInstance().getTenantManager() .getAuthForTenant("TENANT-ID");
Pode importar até 1000 utilizadores de cada vez através de um algoritmo de hash específico.
Node.js
tenantAuth.importUsers([{
uid: 'uid1',
email: 'user1@example.com',
// Must be provided in a byte buffer.
passwordHash: Buffer.from('password-hash-1'),
// Must be provided in a byte buffer.
passwordSalt: Buffer.from('salt1')
},
{
uid: 'uid2',
email: 'user2@example.com',
// Must be provided in a byte buffer.
passwordHash: Buffer.from('password-hash-2'),
// Must be provided in a byte buffer.
passwordSalt: Buffer.from('salt2')
}], {
hash: {
algorithm: 'HMAC_SHA256',
// Must be provided in a byte buffer.
key: Buffer.from('secret')
}
})
.then((results) => {
results.errors.forEach(function(indexedError) {
console.log('Error importing user ' + indexedError.index);
});
})
.catch((error) => {
console.log('Error importing users:', error);
});
Python
users = [ auth.ImportUserRecord( uid='uid1', email='user1@example.com', password_hash=b'password_hash_1', password_salt=b'salt1' ), auth.ImportUserRecord( uid='uid2', email='user2@example.com', password_hash=b'password_hash_2', password_salt=b'salt2' ), ] hash_alg = auth.UserImportHash.hmac_sha256(key=b'secret') try: result = tenant_client.import_users(users, hash_alg=hash_alg) for err in result.errors: print('Failed to import user:', err.reason) except exceptions.FirebaseError as error: print('Error importing users:', error)
Java
List<ImportUserRecord> users = new ArrayList<>(); users.add(ImportUserRecord.builder() .setUid("uid1") .setEmail("user1@example.com") .setPasswordHash("password-hash-1".getBytes()) .setPasswordSalt("salt1".getBytes()) .build()); users.add(ImportUserRecord.builder() .setUid("uid2") .setEmail("user2@example.com") .setPasswordHash("password-hash-2".getBytes()) .setPasswordSalt("salt2".getBytes()) .build()); UserImportHash hmacSha256 = HmacSha256.builder() .setKey("secret".getBytes()) .build(); UserImportResult result = tenantAuth.importUsers(users, UserImportOptions.withHash(hmacSha256)); for (ErrorInfo error : result.getErrors()) { System.out.println("Failed to import user: " + error.getReason()); }
O valor de tenantId
de todos os utilizadores importados é definido como tenantAuth.tenantId
.
Também é possível importar utilizadores sem palavras-passe para um inquilino específico. Estes utilizadores podem ser importados com fornecedores federados e reivindicações personalizadas.
Node.js
tenantAuth.importUsers([{
uid: 'some-uid',
displayName: 'John Doe',
email: 'johndoe@acme.com',
photoURL: 'http://www.example.com/12345678/photo.png',
emailVerified: true,
phoneNumber: '+11234567890',
// Set this user as admin.
customClaims: {admin: true},
// User with SAML provider.
providerData: [{
uid: 'saml-uid',
email: 'johndoe@acme.com',
displayName: 'John Doe',
photoURL: 'http://www.example.com/12345678/photo.png',
providerId: 'saml.acme'
}]
}])
.then(function(results) {
results.errors.forEach(function(indexedError) {
console.log('Error importing user ' + indexedError.index);
});
})
.catch(function(error) {
console.log('Error importing users:', error);
});
Python
users = [ auth.ImportUserRecord( uid='some-uid', display_name='John Doe', email='johndoe@gmail.com', photo_url='http://www.example.com/12345678/photo.png', email_verified=True, phone_number='+11234567890', custom_claims={'admin': True}, # set this user as admin provider_data=[ # user with SAML provider auth.UserProvider( uid='saml-uid', email='johndoe@gmail.com', display_name='John Doe', photo_url='http://www.example.com/12345678/photo.png', provider_id='saml.acme' ) ], ), ] try: result = tenant_client.import_users(users) for err in result.errors: print('Failed to import user:', err.reason) except exceptions.FirebaseError as error: print('Error importing users:', error)
Java
List<ImportUserRecord> users = new ArrayList<>(); users.add(ImportUserRecord.builder() .setUid("some-uid") .setDisplayName("John Doe") .setEmail("johndoe@acme.com") .setPhotoUrl("https://www.example.com/12345678/photo.png") .setEmailVerified(true) .setPhoneNumber("+11234567890") // Set this user as admin. .putCustomClaim("admin", true) // User with SAML provider. .addUserProvider(UserProvider.builder() .setUid("saml-uid") .setEmail("johndoe@acme.com") .setDisplayName("John Doe") .setPhotoUrl("https://www.example.com/12345678/photo.png") .setProviderId("saml.acme") .build()) .build()); UserImportResult result = tenantAuth.importUsers(users); for (ErrorInfo error : result.getErrors()) { System.out.println("Failed to import user: " + error.getReason()); }
Consulte o artigo Importar utilizadores na documentação do SDK de administrador para saber mais.
Validação de identidade
Quando uma app cliente do Identity Platform comunica com um servidor de back-end personalizado, o utilizador com sessão iniciada atual tem de ser identificado nesse servidor. Isto pode ser feito de forma segura através do envio do token de ID do utilizador após o início de sessão bem-sucedido através de uma ligação segura ao seu servidor. Em seguida, o servidor pode validar a integridade e a autenticidade do token de ID.
O SDK de administrador tem um método incorporado para validar e descodificar tokens de ID para um inquilino específico.
Depois de iniciar sessão com êxito de um utilizador num inquilino específico a partir do cliente, obtenha o token de ID do utilizador através do SDK de cliente:
auth.tenantId = 'TENANT-ID';
auth.signInWithEmailAndPassword('user@example.com', 'password')
.then((userCredential) => {
return userCredential.user.getIdToken();
})
.then((idToken) => {
// Send the ID token to server for verification. ID token should be scoped to TENANT-ID.
});
Crie uma instância TenantAwareAuth
no servidor:
Node.js
const tenantAuth = admin.auth().tenantManager().authForTenant('TENANT-ID');
Python
tenant_client = tenant_mgt.auth_for_tenant('TENANT-ID')
Java
TenantAwareFirebaseAuth tenantAuth = FirebaseAuth.getInstance().getTenantManager() .getAuthForTenant("TENANT-ID");
Em seguida, pode validar o token de ID para esse inquilino específico:
Node.js
// idToken comes from the client app
tenantAuth.verifyIdToken(idToken)
.then((decodedToken) => {
let uid = decodedToken.uid;
// This should be set to TENANT-ID. Otherwise auth/mismatching-tenant-id error thrown.
console.log(decodedToken.firebase.tenant);
// ...
}).catch((error) => {
// Handle error
});
Um recurso do lado do servidor pode ser acessível por vários inquilinos com diferentes níveis de acesso. Uma vez que o ID do inquilino pode não ser conhecido antecipadamente neste caso, o token de ID pode ser validado primeiro ao nível do projeto.
admin.auth().verifyIdToken(idToken)
.then((decodedToken) => {
if (decodedToken.firebase.tenant === 'TENANT-ID1') {
// Allow appropriate level of access for TENANT-ID1.
} else if (decodedToken.firebase.tenant === 'TENANT-ID2') {
// Allow appropriate level of access for TENANT-ID2.
} else {
// Block access for all other tenants.
throw new Error('Access not allowed.');
}
}).catch((error) => {
// Handle error
});
Python
# id_token comes from the client app try: decoded_token = tenant_client.verify_id_token(id_token) # This should be set to TENANT-ID. Otherwise TenantIdMismatchError error raised. print('Verified ID token from tenant:', decoded_token['firebase']['tenant']) except tenant_mgt.TenantIdMismatchError: # Token revoked, inform the user to reauthenticate or signOut(). pass
Java
try { // idToken comes from the client app FirebaseToken token = tenantAuth.verifyIdToken(idToken); // TenantId on the FirebaseToken should be set to TENANT-ID. // Otherwise "tenant-id-mismatch" error thrown. System.out.println("Verified ID token from tenant: " + token.getTenantId()); } catch (FirebaseAuthException e) { System.out.println("error verifying ID token: " + e.getMessage()); }
Consulte a documentação do SDK de administrador sobre como validar tokens de ID para saber mais.
Gerir sessões de utilizadores
As sessões da Identity Platform têm uma longa duração. Sempre que um utilizador inicia sessão, as credenciais do utilizador são validadas no servidor da Identity Platform e, em seguida, trocadas por um token de ID de curta duração e um token de atualização de longa duração. Os tokens de ID duram uma hora. Os tokens de atualização nunca expiram, exceto quando um utilizador é desativado, eliminado ou sofre uma alteração significativa na conta (como uma atualização do email ou da palavra-passe).
Em alguns casos, o token de atualização de um utilizador pode ter de ser revogado por motivos de segurança, como o utilizador denunciar um dispositivo perdido ou roubado, a deteção de uma vulnerabilidade geral numa app ou uma fuga em grande escala de tokens ativos. O SDK de administrador fornece uma API para revogar todos os tokens de atualização emitidos para um utilizador especificado de um inquilino específico.
Para começar, precisa de uma instância do TenantAwareAuth
:
Node.js
const tenantAuth = admin.auth().tenantManager().authForTenant('TENANT-ID');
Python
tenant_client = tenant_mgt.auth_for_tenant('TENANT-ID')
Java
TenantAwareFirebaseAuth tenantAuth = FirebaseAuth.getInstance().getTenantManager() .getAuthForTenant("TENANT-ID");
Em seguida, os tokens de atualização podem ser revogados especificando o uid
desse utilizador:
Node.js
// Revoke all refresh tokens for a specified user in a specified tenant for whatever reason.
// Retrieve the timestamp of the revocation, in seconds since the epoch.
tenantAuth.revokeRefreshTokens(uid)
.then(() => {
return tenantAuth.getUser(uid);
})
.then((userRecord) => {
return new Date(userRecord.tokensValidAfterTime).getTime() / 1000;
})
.then((timestamp) => {
console.log('Tokens revoked at: ', timestamp);
});
Python
# Revoke all refresh tokens for a specified user in a specified tenant for whatever reason. # Retrieve the timestamp of the revocation, in seconds since the epoch. tenant_client.revoke_refresh_tokens(uid) user = tenant_client.get_user(uid) # Convert to seconds as the auth_time in the token claims is in seconds. revocation_second = user.tokens_valid_after_timestamp / 1000 print(f'Tokens revoked at: {revocation_second}')
Java
// Revoke all refresh tokens for a specified user in a specified tenant for whatever reason. // Retrieve the timestamp of the revocation, in seconds since the epoch. tenantAuth.revokeRefreshTokens(uid); // accessing the user's TokenValidAfter UserRecord user = tenantAuth.getUser(uid); long timestamp = user.getTokensValidAfterTimestamp() / 1000; System.out.println("the refresh tokens were revoked at: " + timestamp + " (UTC seconds)");
Depois de os tokens de atualização serem revogados, não é possível emitir novos tokens de ID para esse utilizador até que este volte a autenticar-se. No entanto, os tokens de ID existentes permanecem ativos até à respetiva hora de validade natural (uma hora).
Pode verificar se um token de ID válido não expirado não foi revogado especificando o parâmetro checkRevoked
opcional. Isto verifica se um token foi revogado depois de a respetiva integridade e autenticidade terem sido validadas.
Node.js
// Verify the ID token for a specific tenant while checking if the token is revoked by passing
// checkRevoked true.
let checkRevoked = true;
tenantAuth.verifyIdToken(idToken, checkRevoked)
.then(payload => {
// Token is valid.
})
.catch(error => {
if (error.code == 'auth/id-token-revoked') {
// Token has been revoked. Inform the user to re-authenticate or
// signOut() the user.
} else {
// Token is invalid.
}
});
Python
# Verify the ID token for a specific tenant while checking if the token is revoked. try: # Verify the ID token while checking if the token is revoked by # passing check_revoked=True. decoded_token = tenant_client.verify_id_token(id_token, check_revoked=True) # Token is valid and not revoked. uid = decoded_token['uid'] except tenant_mgt.TenantIdMismatchError: # Token belongs to a different tenant. pass except auth.RevokedIdTokenError: # Token revoked, inform the user to reauthenticate or signOut(). pass except auth.UserDisabledError: # Token belongs to a disabled user record. pass except auth.InvalidIdTokenError: # Token is invalid pass
Java
// Verify the ID token for a specific tenant while checking if the token is revoked. boolean checkRevoked = true; try { FirebaseToken token = tenantAuth.verifyIdToken(idToken, checkRevoked); System.out.println("Verified ID token for: " + token.getUid()); } catch (FirebaseAuthException e) { if ("id-token-revoked".equals(e.getErrorCode())) { // Token is revoked. Inform the user to re-authenticate or signOut() the user. } else { // Token is invalid } }
Consulte a documentação do SDK de administrador sobre como gerir sessões para saber mais.
Controlar o acesso com reivindicações personalizadas
O SDK de administração suporta a definição de atributos personalizados em contas de utilizador para um inquilino específico. Estes atributos permitem-lhe implementar diferentes estratégias de controlo de acesso, como o controlo de acesso baseado em funções. Os atributos podem ser usados para dar aos utilizadores diferentes níveis de acesso aplicados pelas regras de segurança da aplicação.
Para começar, obtenha uma instância TenantAwareAuth
para o inquilino correspondente:
Node.js
const tenantAuth = admin.auth().tenantManager().authForTenant('TENANT-ID');
Python
tenant_client = tenant_mgt.auth_for_tenant('TENANT-ID')
Java
TenantAwareFirebaseAuth tenantAuth = FirebaseAuth.getInstance().getTenantManager() .getAuthForTenant("TENANT-ID");
As reivindicações personalizadas podem conter dados confidenciais, pelo que só devem ser definidas a partir de um ambiente de servidor privilegiado através do SDK de administrador.
Node.js
// Set admin privilege on the user corresponding to uid for a specific tenant.
tenantAuth.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.
});
Python
# Set admin privilege on the user corresponding to uid. tenant_client.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.
Java
// Set admin privilege on the user corresponding to uid in a specific tenant. Map<String, Object> claims = new HashMap<>(); claims.put("admin", true); tenantAuth.setCustomUserClaims(uid, claims); // The new custom claims will propagate to the user's ID token the // next time a new one is issued.
Os atributos personalizados definidos recentemente aparecem nos atributos de nível superior da carga útil do token na próxima vez que o utilizador iniciar sessão ou atualizar os respetivos tokens de ID numa sessão existente. No exemplo anterior, o token de ID contém uma reivindicação adicional: {admin: true}
.
Após validar o token de ID e descodificar a respetiva carga útil, as reivindicações personalizadas adicionais podem ser verificadas para aplicar o controlo de acesso.
Node.js
// Verify the ID token first.
tenantAuth.verifyIdToken(idToken).then((claims) => {
if (claims.admin === true) {
// Allow access to requested admin resource.
}
});
Python
# Verify the ID token first. claims = tenant_client.verify_id_token(id_token) if claims['admin'] is True: # Allow access to requested admin resource. pass
Java
// Verify the ID token first. FirebaseToken token = tenantAuth.verifyIdToken(idToken); if (Boolean.TRUE.equals(token.getClaims().get("admin"))) { //Allow access to requested admin resource. } // Verify the ID token first. FirebaseToken decoded = tenantAuth.verifyIdToken(idToken); if (Boolean.TRUE.equals(decoded.getClaims().get("admin"))) { // Allow access to requested admin resource. }
As reivindicações personalizadas de um utilizador existente para um inquilino específico também estão disponíveis como uma propriedade no registo do utilizador.
Node.js
// Lookup the user associated with the specified uid.
tenantAuth.getUser(uid).then((userRecord) => {
// The claims can be accessed on the user record.
console.log(userRecord.customClaims.admin);
});
Python
# Lookup the user associated with the specified uid. user = tenant_client.get_user(uid) # The claims can be accessed on the user record. print(user.custom_claims.get('admin'))
Java
// Lookup the user associated with the specified uid in a specific tenant. UserRecord user = tenantAuth.getUser(uid); System.out.println(user.getCustomClaims().get("admin"));
Consulte a documentação do SDK Admin sobre as Reivindicações personalizadas para saber mais.
Gerar links de ação de email
Com os SDKs de cliente da Identity Platform, pode enviar emails aos utilizadores de um inquilino específico com links que podem usar para repor palavras-passe, validar endereços de email e iniciar sessão com base no email. Estes emails são enviados pela Google e têm opções de personalização limitadas.
Com o SDK Admin, pode gerar estes links de forma programática no âmbito de um inquilino específico.
Para começar, obtenha uma instância TenantAwareAuth
para o inquilino correspondente:
Node.js
const tenantAuth = admin.auth().tenantManager().authForTenant('TENANT-ID');
Python
tenant_client = tenant_mgt.auth_for_tenant('TENANT-ID')
Java
TenantAwareFirebaseAuth tenantAuth = FirebaseAuth.getInstance().getTenantManager() .getAuthForTenant("TENANT-ID");
O exemplo seguinte mostra como gerar um link para validar o email de um utilizador para um inquilino especificado:
Node.js
const actionCodeSettings = {
// URL you want to redirect back to. The domain (www.example.com) for
// this URL must be whitelisted in the Cloud console.
url: 'https://www.example.com/checkout?cartId=1234',
// This must be true for email link sign-in.
handleCodeInApp: true,
iOS: {
bundleId: 'com.example.ios'
},
android: {
packageName: 'com.example.android',
installApp: true,
minimumVersion: '12'
},
// FDL custom domain.
dynamicLinkDomain: 'coolapp.page.link'
};
// Admin SDK API to generate the email verification link.
const userEmail = 'user@example.com';
tenantAuth.generateEmailVerificationLink(userEmail, actionCodeSettings)
.then((link) => {
// Construct email verification template, embed the link and send
// using custom SMTP server.
return sendCustomVerificationEmail(userEmail, displayName, link);
})
.catch((error) => {
// Some error occurred.
});
Python
action_code_settings = auth.ActionCodeSettings( url='https://www.example.com/checkout?cartId=1234', handle_code_in_app=True, ios_bundle_id='com.example.ios', android_package_name='com.example.android', android_install_app=True, android_minimum_version='12', # FDL custom domain. dynamic_link_domain='coolapp.page.link', ) email = 'user@example.com' link = tenant_client.generate_email_verification_link(email, action_code_settings) # Construct email from a template embedding the link, and send # using a custom SMTP server. send_custom_email(email, link)
Java
ActionCodeSettings actionCodeSettings = ActionCodeSettings.builder() // URL you want to redirect back to. The domain (www.example.com) for // this URL must be whitelisted in the GCP Console. .setUrl("https://www.example.com/checkout?cartId=1234") // This must be true for email link sign-in. .setHandleCodeInApp(true) .setIosBundleId("com.example.ios") .setAndroidPackageName("com.example.android") .setAndroidInstallApp(true) .setAndroidMinimumVersion("12") // FDL custom domain. .setDynamicLinkDomain("coolapp.page.link") .build(); String link = tenantAuth.generateEmailVerificationLink(email, actionCodeSettings); // Construct email verification template, embed the link and send // using custom SMTP server. sendCustomEmail(email, displayName, link);
Estão disponíveis mecanismos semelhantes para gerar links de reposição de palavra-passe e
início de sessão baseados em email. Tenha em atenção que, quando gera um link de ação de email num contexto de inquilino, o ID do inquilino tem de ser analisado a partir do link e definido na instância do cliente Auth
antes de o código poder ser aplicado.
const actionCodeUrl = firebase.auth.ActionCodeURL.parseLink(window.location.href);
// A one-time code, used to identify and verify a request.
const code = actionCodeUrl.code;
// The tenant ID being used to trigger the email action.
const tenantId = actionCodeUrl.tenantId;
auth.tenantId = tenantId;
// Apply the action code.
auth.applyActionCode(actionCode)
.then(() => {
// User's email is now verified.
})
.catch((error) => {
// Handle error.
});
Consulte o artigo Links de ações de email na documentação do SDK Admin para saber mais.
Mensagens de erro
A tabela seguinte apresenta mensagens de erro comuns que pode encontrar.
Código de erro | Descrição e passos de resolução |
---|---|
auth/billing-not-enabled |
Esta funcionalidade requer a ativação da faturação. |
auth/invalid-display-name |
O campo displayName tem de ser uma string válida. |
auth/invalid-name |
O nome do recurso fornecido é inválido. |
auth/invalid-page-token |
O token de página tem de ser uma string não vazia válida. |
auth/invalid-project-id |
Projeto principal inválido. O projeto principal não tem ou não tinha a funcionalidade de multi-inquilino ativada. |
auth/invalid-tenant-id |
O ID do inquilino tem de ser uma string não vazia válida. |
auth/mismatching-tenant-id |
O ID do inquilino do utilizador não corresponde ao ID do inquilino TenantAwareAuth atual.
|
auth/missing-display-name |
O recurso que está a ser criado ou editado não tem um nome a apresentar válido. |
auth/insufficient-permission |
O utilizador não tem autorização suficiente para aceder ao recurso pedido ou para executar a operação específica do inquilino. |
auth/quota-exceeded |
A quota do projeto para a operação especificada foi excedida. |
auth/tenant-not-found |
Não existe nenhum inquilino correspondente ao identificador fornecido. |
auth/unsupported-tenant-operation |
Esta operação não é suportada num contexto multiinquilino. |
auth/invalid-testing-phone-number |
Foi fornecido um número de telefone de teste inválido ou um código de teste inválido. |
auth/test-phone-number-limit-exceeded |
Excedeu o número máximo de pares de códigos e números de telefone de teste permitidos. |