Como gerenciar locatários do Identity Platform de maneira programática
Este documento explica como usar o SDK Admin do Identity Platform para gerenciar locatários e usuários de maneira programática. Algumas atividades que podem ser executadas como administrador incluem:
Gerenciamento de usuários: crie, atualize, exclua e liste usuários de um locatário específico.
Verificação de identidade: identifique os usuários de um app para restringir o acesso aos recursos no seu servidor.
Importar usuários: migre usuários de um sistema de autenticação externo ou de outro projeto ou locatário do Identity Platform.
Controle de acesso com declarações personalizadas: defina atributos personalizados em contas de usuário para um locatário específico e implemente várias estratégias de controle de acesso, como controle de acesso baseado em papel.
Gerenciamento da sessão do usuário: revogue os tokens de atualização de um usuário para um locatário específico.
Links de ação de e-mail: gere links de e-mail personalizados para redefinição de senha, login por link de e-mail e verificação de e-mail para usuários de um locatário específico.
Gerenciamento de locatários: crie, liste, receba, atualize e exclua locatários para um projeto específico do Identity Platform.
Gerenciar provedores de OIDC e SAML em locatários: gerencie de maneira programática as configurações de OIDC e SAML em um locatário especificado.
Antes de começar
Instale o SDK Admin para Node.js, Java, Python, Go ou C#.
Ative a multilocação no seu projeto do Google Cloud.
Recursos compatíveis
A tabela a seguir lista os recursos compatíveis com cada SDK em um ambiente de vários locatários:
Feature | Node.js | Java | Python | Go | C# |
---|---|---|---|---|---|
Emissão de tokens personalizada | |||||
Como verificar tokens de ID | |||||
Gerenciamento de usuários | |||||
Como controlar o acesso com declarações personalizadas | |||||
Como revogar tokens de atualização | |||||
Como importar usuários | |||||
Como gerar links de ação de e-mail | |||||
Autenticação multifator | |||||
Como gerenciar configurações do provedor SAML/OIDC | |||||
Gerenciamento de cookies de sessão |
A tabela a seguir mostra os métodos de login que podem ser configurados usando o SDK Admin e o console do Google Cloud em um contexto específico de locatário:
Recurso | Console do Google Cloud | SDK Admin |
---|---|---|
OIDC | ||
SAML | ||
Mídia | ||
Telefone | ||
Autenticação multifator | ||
Anônimo |
Gestão de inquilinos
Com o SDK Admin, é possível gerenciar locatários de maneira programática usando um um ambiente de servidor seguro em vez de usar o console do Google Cloud. Isso inclui a capacidade de criar, listar, conseguir, modificar ou excluir locatários.
Cada locatário contém seus próprios provedores de identidade, configurações e conjuntos de usuários.
Operações de gerenciamento de configuração (CRUD) estão disponíveis na instância do projeto
pai usando o admin.auth().tenantManager()
.
Uma configuração de locatário fornece informações sobre um locatário, como nome de exibição, identificador de locatário e configuração de autenticação de e-mail.
Todas as outras configurações (como domínios permitidos e URIs de redirecionamento autenticados) de um locatário são herdadas do projeto pai. Elas precisam ser gerenciadas usando o console do Google Cloud.
Para operações como gerenciamento de usuários específico do locatário, configuração de provedores
OIDC/SAML e geração de links de e-mail, você precisará de uma instância
TenantAwareAuth
para o locatário de destino (identificado pelo 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 gerenciamento de usuários, APIs de gerenciamento de provedor OIDC/SAML e
APIs de geração de link de e-mail estarão dentro do escopo desse locatário (usando a
instância TenantAwareAuth
).
Como conseguir um locatário atual
O SDK Admin fornece o método getTenant()
, que busca informações
sobre um locatário com base em seu tenantId
(um identificador exclusivo para o locatário).
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());
Esse método retorna um objeto Tenant
correspondente ao tenantId
.
Se o tenantId
fornecido não pertencer a um locatário atual, a promessa
retornada será 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()
retorna uma
instância TenantAwareAuth
que estende
BaseAuth
.
A classe Auth
também estende BaseAuth
.
BaseAuth
fornece APIs para gerenciar usuários e configura provedores OIDC/SAML
em contextos diferentes. Para Auth
, o contexto está no nível do projeto pai.
Para TenantAwareAuth
, o contexto está no nível de locatário (o locatário é
determinado pelo ID do locatário). O getTenant()
do método será resolvido com informações básicas
sobre o locatário (como ID de locatário, nome de exibição e configurações do provedor de e-mail),
mas para chamar APIs nesse locatário, você precisa usar
authForTenant(tenantFromGetTenant.tenantId)
.
Como criar um locatário
Use o método createTenant()
para criar uma nova configuração de locatário:
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());
É possível fornecer qualquer combinação dessas propriedades:
Property | Tipo | Descrição |
---|---|---|
displayName |
string |
O nome de exibição do locatário. Precisa ter de 4 a 20 caracteres, contendo letras, dígitos e hífens e começar com uma letra. |
emailSignInConfig |
{ enable: boolean, passwordRequired: boolean } |
Configuração do provedor de login de e-mail. Isso inclui se o provedor de e-mail está ativado e se a senha é necessária para o login por e-mail. Quando não é obrigatório, o login de e-mail pode ser realizado com senha ou usando o login por link de e-mail. |
multiFactorConfig |
{ state: 'DISABLED' | 'ENABLED', factorIds: string[] } |
Se a autenticação multifator está ativada para o locatário ou não, e quais tipos de fator são permitidos. Atualmente, o único código de fator compatível é phone .
|
testPhoneNumbers |
{ string: string } |
Um mapa de números de telefone e os códigos de autenticação multifator associados a fim de se registrar 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 retorna um objeto Tenant
para o locatário recém-criado.
Como atualizar um locatário
Use o método updateTenant()
para modificar os dados de um locatário atual. É necessário
especificar o tenantId
e as propriedades a serem atualizadas para o locatário em questão.
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 atual não será
modificado.
O método retorna um objeto Tenant
atualizado após a conclusão. Se o tenantId
fornecido não pertencer a um locatário atual, a promessa retornada será rejeitada
com um erro auth/tenant-not-found
.
Como excluir um locatário
É possível excluir um locatário usando o 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 retorna um resultado vazio quando a exclusão é concluída com sucesso.
Se o tenantId
fornecido não pertencer a um locatário atual, a promessa
retornada será rejeitada com um erro auth/tenant-not-found
.
Como listar locatários
Use o método listTenants()
para listar os locatários atuais:
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 locatários, além de um token de próxima página para
listar o próximo lote de locatário. Quando todos os locatários já tiverem sido listados,
nenhum pageToken
será retornado.
Se nenhum campo maxResults
for especificado, o padrão será 1.000 locatários por lote.
Esse também é o número máximo de locatários permitidos por vez.
Qualquer valor maior que o máximo lançará um erro de argumento.
Se nenhum pageToken
for especificado, o método lista os locatários desde o
início.
Como gerenciar provedores SAML e OIDC de forma programática
O SDK Admin fornece APIs para gerenciar as configurações do provedor da Linguagem de marcação para autorização de segurança (SAML, na sigla em inglês) 2.0 e do OpenID Connect (OIDC) de maneira programática em um ambiente de servidor seguro.
Com o SDK Admin, você pode gerenciar esses provedores para um locatário específico. Isso é semelhante ao gerenciamento de provedores OIDC e SAML no nível do projeto.
Para gerenciar provedores de um locatário, primeiro crie 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, você pode realizar operações comuns, como criar, modificar ou excluir provedores de um locatário.
Como criar um provedor
O código a seguir mostra como criar um provedor SAML para um locatário:
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());
Como modificar um provedor
O código a seguir mostra como modificar um provedor:
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());
Como conseguir um provedor
O código a seguir mostra como recuperar a configuração do provedor para um locatário específico usando o ID do provedor:
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());
Como listar provedores
O código a seguir mostra como listar configurações de provedor de um determinado locatário:
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()); }
Como excluir um provedor
O código a seguir mostra como excluir um provedor:
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 provedores de OIDC são gerenciados de maneira semelhante aos provedores de OIDC no nível do projeto, mas
podem ser gerenciados na instância TenantAwareAuth
correspondente, em vez de
uma instância no nível do projeto Auth
.
Para saber mais, consulte Como gerenciar provedores SAML e OIDC de maneira programática.
Como gerenciar usuários específicos de locatário
É possível usar o SDK Admin para criar, recuperar, atualizar, excluir e listar todos os usuários de um locatário específico.
Para começar, você precisa de uma instância de TenantAwareAuth
para o locatário 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");
Como receber um usuário
É possível recuperar um usuário específico de locatário 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());
Você também pode identificar um usuário por e-mail:
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());
Criar um usuário
Use o método createUser()
para criar novos usuários para um locatário específico.
Ao criar um novo usuário, fornecer um uid
é opcional. Se não for especificado,
o Identity Platform provisionará um único.
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());
Como modificar um usuário
É possível modificar os usuários atuais especificando uid
deles para
o 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());
Como excluir um usuário
O exemplo a seguir mostra como excluir um usuário com base no 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 usuários
Para recuperar uma lista inteira de usuários de um locatário específico em lotes, use o
método listUsers()
. Cada lote conterá uma lista de registros de usuário e um
token de próxima página, caso outros usuários permaneçam.
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 Admin sobre como gerenciar usuários para saber mais.
Como importar usuários
É possível usar o SDK Admin para importar usuários em massa para um locatário específico com privilégios elevados. Isso oferece vários benefícios, como a capacidade de migrar usuários de outro produto do Identity Platform, de outro locatário ou de um sistema de autenticação externo usando um algoritmo de hash diferente. Também é possível importar usuários com provedores federados (como SAML e OIDC) e declarações personalizadas diretamente em massa.
Para começar, consiga uma instância TenantAwareAuth
para o locatário 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");
Você pode importar até mil usuários de uma só vez usando 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()); }
Todos os usuários importados terão o tenantId
definido como tenantAuth.tenantId
.
Os usuários sem senhas também podem ser importados para um locatário específico. Esses usuários podem ser importados com provedores federados e declaraçõ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 Importar usuários na documentação do SDK Admin para saber mais.
Verificação da identidade
Quando um aplicativo cliente do Identity Platform se comunica com um servidor de back-end personalizado, o usuário conectado atual precisa ser identificado nesse servidor. Isso pode ser feito com segurança enviando o token de ID do usuário após o login bem-sucedido usando uma conexão segura com seu servidor. O servidor pode verificar a integridade e a autenticidade do token de ID.
O SDK Admin tem um método integrado para verificar e decodificar tokens de ID para um locatário específico.
Depois de fazer login com sucesso em um usuário a um locatário específico do cliente, recupere o token de ID do usuário usando o SDK do 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");
Assim, você pode verificar o token de ID para esse locatário 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 acessado por vários locatários com diferentes níveis de acesso. Como o ID do locatário pode não ser conhecido com antecedência neste caso, o token de ID pode ser verificado primeiro no 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()); }
Veja mais informações no documento sobre como verificar os tokens de ID do SDK Admin.
Como gerenciar sessões de usuários
As sessões do Identity Platform têm longa duração. Sempre que um usuário faz login, as credenciais do usuário são verificadas no servidor do Identity Platform e 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 por uma hora. Os tokens de atualização nunca expiram, exceto quando um usuário é desativado, excluído ou passa por uma grande alteração de conta (como uma atualização de e-mail ou senha).
Em alguns casos, o token de atualização de um usuário pode precisar ser revogado por motivos de segurança, como se o usuário relata um dispositivo perdido ou roubado, a descoberta de uma vulnerabilidade geral em um app ou um vazamento em grande escala de tokens ativos. O SDK Admin fornece uma API para revogar todos os tokens de atualização emitidos para um usuário especificado de um locatário específico.
Para começar, você precisa de 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");
Os tokens de atualização podem ser revogados especificando o uid
desse usuário:
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('Tokens revoked at: {0}'.format(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 que os tokens de atualização forem revogados, nenhum novo token de ID poderá ser emitido para esse usuário até que ele seja autenticado novamente. No entanto, os tokens de ID atuais permanecerão ativos até o tempo de expiração natural (uma hora).
É possível verificar se um token de ID válido não expirado não é revogado especificando
o parâmetro checkRevoked
opcional. Ele verifica se um token é revogado depois
que a integridade e a autenticidade dele são verificadas.
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 } }
Veja a documentação do SDK Admin sobre como gerenciar sessões para saber mais.
Como controlar o acesso com declarações personalizadas
O SDK Admin é compatível com a definição de atributos personalizados em contas de usuário para um locatário específico. Esses atributos permitem implementar diferentes estratégias de controle de acesso, como o controle de acesso baseado em papéis. Os atributos podem ser usados para oferecer aos usuários diferentes níveis de acesso aplicados pelas regras de segurança do aplicativo.
Para começar, consiga uma instância de TenantAwareAuth
para o locatário 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 declarações personalizadas podem conter dados confidenciais. Portanto, elas só podem ser definidas em um ambiente de servidor privilegiado usando o SDK Admin.
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 recém-definidos serão exibidos nos atributos de nível superior do payload
do token na próxima vez que o usuário fizer login ou atualizar os tokens de ID em uma
sessão atual. No exemplo anterior, o token de ID contém uma declaração
adicional: {admin: true}
.
Depois de verificar o token de ID e decodificar o payload, as declarações personalizadas adicionais podem ser verificadas para impor o controle 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 declarações personalizadas para um usuário atual de um locatário específico também estão disponíveis como uma propriedade no registro do usuário.
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 declarações personalizadas para saber mais.
Como gerar links de ação de e-mail
Com os SDKs de cliente do Identity Platform, você pode enviar usuários de e-mails de locatários específicos com links que eles podem usar para redefinições de senha, verificação de endereço de e-mail e login com base em e-mail. Esses e-mails são enviados pelo Google e têm personalização limitada.
Com o SDK Admin, é possível gerar esses links de maneira programática no escopo de um locatário específico.
Para começar, consiga uma instância de TenantAwareAuth
para o locatário 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 a seguir mostra como gerar um link para verificar o e-mail de um usuário para um locatário 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);
Mecanismos semelhantes estão disponíveis para gerar redefinição de senha e
links de login com base em e-mail. Ao gerar um link de ação de e-mail em um
contexto de locatário, o ID do locatário precisa ser analisado a partir do link e definido na instância
Auth
do cliente antes que o código possa 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 Links de ação por e-mail na documentação do SDK Admin para saber mais.
Mensagens de erro
A tabela a seguir lista as mensagens de erro comuns que você pode encontrar.
Código do erro | Etapas de resolução e descrição |
---|---|
auth/billing-not-enabled |
Esse recurso exige que o faturamento esteja ativado. |
auth/invalid-display-name |
O campo displayName precisa ser uma string válida. |
auth/invalid-name |
O nome do recurso fornecido é inválido. |
auth/invalid-page-token |
O token de página precisa ser uma string não vazia válida. |
auth/invalid-project-id |
Projeto pai inválido. O projeto pai não ativa ou não ativou a multilocação. |
auth/invalid-tenant-id |
O ID do locatário precisa ser uma string não vazia válida. |
auth/mismatching-tenant-id |
O ID de locatário do usuário não corresponde ao ID do locatário
TenantAwareAuth atual.
|
auth/missing-display-name |
O recurso que está sendo criado ou editado está sem um nome de exibição válido. |
auth/insufficient-permission |
O usuário não tem permissão suficiente para acessar o recurso solicitado ou executar a operação de locatário específica. |
auth/quota-exceeded |
A cota do projeto para a operação especificada foi excedida. |
auth/tenant-not-found |
Não há locatário correspondente ao identificador fornecido. |
auth/unsupported-tenant-operation |
Essa operação não é compatível com um contexto de vários locatários. |
auth/invalid-testing-phone-number |
Um número de telefone de teste inválido ou um código de teste inválido foi fornecido. |
auth/test-phone-number-limit-exceeded |
O número máximo permitido de números de telefone e códigos de teste foi excedido. |