Como migrar usuários de um app
Neste documento, mostramos como migrar usuários de um aplicativo atual para o Identity Platform.
Antes de começar
Como usar o SDK Admin
O SDK Admin permite importar usuários sem exportar dados de usuários para CSV ou JSON. É possível importar usuários para todos os provedores de identidade do Identity Platform, incluindo OAuth, SAML e OIDC.
Até mil usuários podem ser importados em uma única chamada de API. A operação de importação
é otimizada para velocidade e não verifica se há campos duplicados. Importar um usuário
que entra em conflito com um uid
atual substituirá esse usuário. Importar um
usuário com qualquer outro campo duplicado (como email
) resultará em
outro usuário com o mesmo valor.
O SDK Admin tenta fazer upload de toda a lista de usuários fornecidos, mesmo quando ocorre um erro específico do usuário. A operação retorna um resultado com o resumo das importações bem-sucedidas e com falha. Os detalhes do erro são retornados a cada importação de usuário com falha.
Como importar usuários com senhas com hash HMAC
Os algoritmos de hash HMAC incluem: HMAC_MD5
, HMAC_SHA1
, HMAC_SHA256
e
HMAC_SHA512
. Você precisará fornecer a chave de assinante do hash.
Node.js
getAuth() .importUsers( [ { uid: 'some-uid', email: 'user@example.com', // Must be provided in a byte buffer. passwordHash: Buffer.from('password-hash'), // Must be provided in a byte buffer. passwordSalt: Buffer.from('salt'), }, ], { hash: { algorithm: 'HMAC_SHA256', // Must be provided in a byte buffer. key: Buffer.from('secret'), }, } ) .then((results) => { results.errors.forEach((indexedError) => { console.log(`Error importing user ${indexedError.index}`); }); }) .catch((error) => { console.log('Error importing users :', error); });
Java
try { List<ImportUserRecord> users = Collections.singletonList(ImportUserRecord.builder() .setUid("some-uid") .setEmail("user@example.com") .setPasswordHash("password-hash".getBytes()) .setPasswordSalt("salt".getBytes()) .build()); UserImportOptions options = UserImportOptions.withHash( HmacSha256.builder() .setKey("secret".getBytes()) .build()); UserImportResult result = FirebaseAuth.getInstance().importUsers(users, options); for (ErrorInfo indexedError : result.getErrors()) { System.out.println("Failed to import user: " + indexedError.getReason()); } } catch (FirebaseAuthException e) { System.out.println("Error importing users: " + e.getMessage()); }
Python
users = [ auth.ImportUserRecord( uid='some-uid', email='user@example.com', password_hash=b'password_hash', password_salt=b'salt' ), ] hash_alg = auth.UserImportHash.hmac_sha256(key=b'secret') try: result = auth.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)
Go
users := []*auth.UserToImport{ (&auth.UserToImport{}). UID("some-uid"). Email("user@example.com"). PasswordHash([]byte("password-hash")). PasswordSalt([]byte("salt")), } h := hash.HMACSHA256{ Key: []byte("secret"), } result, err := client.ImportUsers(ctx, users, auth.WithHash(h)) if err != nil { log.Fatalln("Error importing users", err) } for _, e := range result.Errors { log.Println("Failed to import user", e.Reason) }
Como importar usuários com senhas com hash MD5, SHA e PBKDF
Os algoritmos de hash MD5, SHA e PBKDF incluem MD5
, SHA1
, SHA256
,
SHA512
, PBKDF_SHA1
e PBKDF2_SHA256
. Você precisará fornecer as rodadas
usadas para gerar o hash da senha (entre 0 e 8192 para MD5
, entre 1
e 8192 para SHA1
, SHA256
e SHA512
, e entre 0 e 120000 para
PBKDF_SHA1
e PBKDF2_SHA256
).
Node.js
getAuth() .importUsers( [ { uid: 'some-uid', email: 'user@example.com', // Must be provided in a byte buffer. passwordHash: Buffer.from('password-hash'), // Must be provided in a byte buffer. passwordSalt: Buffer.from('salt'), }, ], { hash: { algorithm: 'PBKDF2_SHA256', rounds: 100000, }, } ) .then((results) => { results.errors.forEach((indexedError) => { console.log(`Error importing user ${indexedError.index}`); }); }) .catch((error) => { console.log('Error importing users :', error); });
Java
try { List<ImportUserRecord> users = Collections.singletonList(ImportUserRecord.builder() .setUid("some-uid") .setEmail("user@example.com") .setPasswordHash("password-hash".getBytes()) .setPasswordSalt("salt".getBytes()) .build()); UserImportOptions options = UserImportOptions.withHash( Pbkdf2Sha256.builder() .setRounds(100000) .build()); UserImportResult result = FirebaseAuth.getInstance().importUsers(users, options); for (ErrorInfo indexedError : result.getErrors()) { System.out.println("Failed to import user: " + indexedError.getReason()); } } catch (FirebaseAuthException e) { System.out.println("Error importing users: " + e.getMessage()); }
Python
users = [ auth.ImportUserRecord( uid='some-uid', email='user@example.com', password_hash=b'password_hash', password_salt=b'salt' ), ] hash_alg = auth.UserImportHash.pbkdf2_sha256(rounds=100000) try: result = auth.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)
Go
users := []*auth.UserToImport{ (&auth.UserToImport{}). UID("some-uid"). Email("user@example.com"). PasswordHash([]byte("password-hash")). PasswordSalt([]byte("salt")), } h := hash.PBKDF2SHA256{ Rounds: 100000, } result, err := client.ImportUsers(ctx, users, auth.WithHash(h)) if err != nil { log.Fatalln("Error importing users", err) } for _, e := range result.Errors { log.Println("Failed to import user", e.Reason) }
Como importar usuários com senhas em hash SCRYPT padrão
O SDK Admin é compatível com o algoritmo SCRYPT
padrão, bem como uma
versão modificada interna. Os seguintes
parâmetros são necessários:
memoryCost
: o custo de CPU/memória do algoritmo de hash.parallelization
: o carregamento em paralelo do algoritmo de hash.blockSize
: o tamanho do bloco (normalmente oito) do algoritmo de hash.derivedKeyLength
: o comprimento da chave derivada do algoritmo de hash.
Node.js
getAuth() .importUsers( [ { uid: 'some-uid', email: 'user@example.com', // Must be provided in a byte buffer. passwordHash: Buffer.from('password-hash'), // Must be provided in a byte buffer. passwordSalt: Buffer.from('salt'), }, ], { hash: { algorithm: 'STANDARD_SCRYPT', memoryCost: 1024, parallelization: 16, blockSize: 8, derivedKeyLength: 64, }, } ) .then((results) => { results.errors.forEach((indexedError) => { console.log(`Error importing user ${indexedError.index}`); }); }) .catch((error) => { console.log('Error importing users :', error); });
Java
try { List<ImportUserRecord> users = Collections.singletonList(ImportUserRecord.builder() .setUid("some-uid") .setEmail("user@example.com") .setPasswordHash("password-hash".getBytes()) .setPasswordSalt("salt".getBytes()) .build()); UserImportOptions options = UserImportOptions.withHash( StandardScrypt.builder() .setMemoryCost(1024) .setParallelization(16) .setBlockSize(8) .setDerivedKeyLength(64) .build()); UserImportResult result = FirebaseAuth.getInstance().importUsers(users, options); for (ErrorInfo indexedError : result.getErrors()) { System.out.println("Failed to import user: " + indexedError.getReason()); } } catch (FirebaseAuthException e) { System.out.println("Error importing users: " + e.getMessage()); }
Python
users = [ auth.ImportUserRecord( uid='some-uid', email='user@example.com', password_hash=b'password_hash', password_salt=b'salt' ), ] hash_alg = auth.UserImportHash.standard_scrypt( memory_cost=1024, parallelization=16, block_size=8, derived_key_length=64) try: result = auth.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)
Go
users := []*auth.UserToImport{ (&auth.UserToImport{}). UID("some-uid"). Email("user@example.com"). PasswordHash([]byte("password-hash")). PasswordSalt([]byte("salt")), } h := hash.StandardScrypt{ MemoryCost: 1024, Parallelization: 16, BlockSize: 8, DerivedKeyLength: 64, } result, err := client.ImportUsers(ctx, users, auth.WithHash(h)) if err != nil { log.Fatalln("Error importing users", err) } for _, e := range result.Errors { log.Println("Failed to import user", e.Reason) }
Como importar usuários com senhas em hash SCRYPT do Identity Platform
O Identity Platform e o Firebase usam uma
versão modificada
do algoritmo SCRYPT
. Se você precisar migrar usuários do Firebase para o
Identity Platform ou de um projeto do Identity Platform para outro,
precisará dos parâmetros de hash internos.
Para acessar os parâmetros no Identity Platform:
- Abra a página Usuários no console do Google Cloud.
- Clique em Importar usuários. Os parâmetros de hash da senha são exibidos.
Para acessar os parâmetros no Firebase:
Abra a guia Usuários no Console do Firebase.
Selecione Parâmetros de hash de senha na lista suspensa no canto superior direito da lista de usuários. Os parâmetros de hash da senha são exibidos.
No seu código, você precisará fornecer os seguintes itens:
key
: a chave do assinante normalmente fornecida na codificaçãobase64
.saltSeparator
: (opcional) o separador de salt normalmente fornecido na codificaçãobase64
.rounds
: o número de rodadas usadas para gerar o hash das senhas.memoryCost
: o custo de memória necessário para o algoritmo.
Node.js
getAuth() .importUsers( [ { uid: 'some-uid', email: 'user@example.com', // Must be provided in a byte buffer. passwordHash: Buffer.from('base64-password-hash', 'base64'), // Must be provided in a byte buffer. passwordSalt: Buffer.from('base64-salt', 'base64'), }, ], { hash: { algorithm: 'SCRYPT', // All the parameters below can be obtained from the Firebase Console's users section. // Must be provided in a byte buffer. key: Buffer.from('base64-secret', 'base64'), saltSeparator: Buffer.from('base64SaltSeparator', 'base64'), rounds: 8, memoryCost: 14, }, } ) .then((results) => { results.errors.forEach((indexedError) => { console.log(`Error importing user ${indexedError.index}`); }); }) .catch((error) => { console.log('Error importing users :', error); });
Java
try { List<ImportUserRecord> users = Collections.singletonList(ImportUserRecord.builder() .setUid("some-uid") .setEmail("user@example.com") .setPasswordHash(BaseEncoding.base64().decode("password-hash")) .setPasswordSalt(BaseEncoding.base64().decode("salt")) .build()); UserImportOptions options = UserImportOptions.withHash( Scrypt.builder() // All the parameters below can be obtained from the Firebase Console's "Users" // section. Base64 encoded parameters must be decoded into raw bytes. .setKey(BaseEncoding.base64().decode("base64-secret")) .setSaltSeparator(BaseEncoding.base64().decode("base64-salt-separator")) .setRounds(8) .setMemoryCost(14) .build()); UserImportResult result = FirebaseAuth.getInstance().importUsers(users, options); for (ErrorInfo indexedError : result.getErrors()) { System.out.println("Failed to import user: " + indexedError.getReason()); } } catch (FirebaseAuthException e) { System.out.println("Error importing users: " + e.getMessage()); }
Python
users = [ auth.ImportUserRecord( uid='some-uid', email='user@example.com', password_hash=base64.urlsafe_b64decode('password_hash'), password_salt=base64.urlsafe_b64decode('salt') ), ] # All the parameters below can be obtained from the Firebase Console's "Users" # section. Base64 encoded parameters must be decoded into raw bytes. hash_alg = auth.UserImportHash.scrypt( key=base64.b64decode('base64_secret'), salt_separator=base64.b64decode('base64_salt_separator'), rounds=8, memory_cost=14 ) try: result = auth.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)
Go
b64URLdecode := func(s string) []byte { b, err := base64.URLEncoding.DecodeString(s) if err != nil { log.Fatalln("Failed to decode string", err) } return b } b64Stddecode := func(s string) []byte { b, err := base64.StdEncoding.DecodeString(s) if err != nil { log.Fatalln("Failed to decode string", err) } return b } // Users retrieved from Firebase Auth's backend need to be base64URL decoded users := []*auth.UserToImport{ (&auth.UserToImport{}). UID("some-uid"). Email("user@example.com"). PasswordHash(b64URLdecode("password-hash")). PasswordSalt(b64URLdecode("salt")), } // All the parameters below can be obtained from the Firebase Console's "Users" // section. Base64 encoded parameters must be decoded into raw bytes. h := hash.Scrypt{ Key: b64Stddecode("base64-secret"), SaltSeparator: b64Stddecode("base64-salt-separator"), Rounds: 8, MemoryCost: 14, } result, err := client.ImportUsers(ctx, users, auth.WithHash(h)) if err != nil { log.Fatalln("Error importing users", err) } for _, e := range result.Errors { log.Println("Failed to import user", e.Reason) }
Como importar usuários com senhas de hash BCRYPT
Não é necessário usar parâmetros ou salts adicionais para senhas com hash
BCRYPT
.
Node.js
getAuth() .importUsers( [ { uid: 'some-uid', email: 'user@example.com', // Must be provided in a byte buffer. passwordHash: Buffer.from('password-hash'), }, ], { hash: { algorithm: 'BCRYPT', }, } ) .then((results) => { results.errors.forEach((indexedError) => { console.log(`Error importing user ${indexedError.index}`); }); }) .catch((error) => { console.log('Error importing users :', error); });
Java
try { List<ImportUserRecord> users = Collections.singletonList(ImportUserRecord.builder() .setUid("some-uid") .setEmail("user@example.com") .setPasswordHash("password-hash".getBytes()) .setPasswordSalt("salt".getBytes()) .build()); UserImportOptions options = UserImportOptions.withHash(Bcrypt.getInstance()); UserImportResult result = FirebaseAuth.getInstance().importUsers(users, options); for (ErrorInfo indexedError : result.getErrors()) { System.out.println("Failed to import user: " + indexedError.getReason()); } } catch (FirebaseAuthException e) { System.out.println("Error importing users: " + e.getMessage()); }
Python
users = [ auth.ImportUserRecord( uid='some-uid', email='user@example.com', password_hash=b'password_hash', password_salt=b'salt' ), ] hash_alg = auth.UserImportHash.bcrypt() try: result = auth.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)
Go
users := []*auth.UserToImport{ (&auth.UserToImport{}). UID("some-uid"). Email("user@example.com"). PasswordHash([]byte("password-hash")). PasswordSalt([]byte("salt")), } h := hash.Bcrypt{} result, err := client.ImportUsers(ctx, users, auth.WithHash(h)) if err != nil { log.Fatalln("Error importing users", err) } for _, e := range result.Errors { log.Println("Failed to import user", e.Reason) }
Como importar usuários sem senhas
Se os usuários se autenticarem com um provedor de identidade externo usando OAuth, SAML ou OIDC, você não terá acesso direto à senha.
Node.js
getAuth() .importUsers([ { uid: 'some-uid', displayName: 'John Doe', email: 'johndoe@gmail.com', photoURL: 'http://www.example.com/12345678/photo.png', emailVerified: true, phoneNumber: '+11234567890', // Set this user as admin. customClaims: { admin: true }, // User with Google provider. providerData: [ { uid: 'google-uid', email: 'johndoe@gmail.com', displayName: 'John Doe', photoURL: 'http://www.example.com/12345678/photo.png', providerId: 'google.com', }, ], }, ]) .then((results) => { results.errors.forEach((indexedError) => { console.log(`Error importing user ${indexedError.index}`); }); }) .catch((error) => { console.log('Error importing users :', error); });
Java
try { List<ImportUserRecord> users = Collections.singletonList(ImportUserRecord.builder() .setUid("some-uid") .setDisplayName("John Doe") .setEmail("johndoe@gmail.com") .setPhotoUrl("http://www.example.com/12345678/photo.png") .setEmailVerified(true) .setPhoneNumber("+11234567890") .putCustomClaim("admin", true) // set this user as admin .addUserProvider(UserProvider.builder() // user with Google provider .setUid("google-uid") .setEmail("johndoe@gmail.com") .setDisplayName("John Doe") .setPhotoUrl("http://www.example.com/12345678/photo.png") .setProviderId("google.com") .build()) .build()); UserImportResult result = FirebaseAuth.getInstance().importUsers(users); for (ErrorInfo indexedError : result.getErrors()) { System.out.println("Failed to import user: " + indexedError.getReason()); } } catch (FirebaseAuthException e) { System.out.println("Error importing users: " + e.getMessage()); }
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 Google provider auth.UserProvider( uid='google-uid', email='johndoe@gmail.com', display_name='John Doe', photo_url='http://www.example.com/12345678/photo.png', provider_id='google.com' ) ], ), ] try: result = auth.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)
Go
users := []*auth.UserToImport{ (&auth.UserToImport{}). UID("some-uid"). DisplayName("John Doe"). Email("johndoe@gmail.com"). PhotoURL("http://www.example.com/12345678/photo.png"). EmailVerified(true). PhoneNumber("+11234567890"). CustomClaims(map[string]interface{}{"admin": true}). // set this user as admin ProviderData([]*auth.UserProvider{ // user with Google provider { UID: "google-uid", Email: "johndoe@gmail.com", DisplayName: "John Doe", PhotoURL: "http://www.example.com/12345678/photo.png", ProviderID: "google.com", }, }), } result, err := client.ImportUsers(ctx, users) if err != nil { log.Fatalln("Error importing users", err) } for _, e := range result.Errors { log.Println("Failed to import user", e.Reason) }
Observe que providerId
é usado em todo o Identity Platform para descrever um
provedor específico. Para provedores OIDC e SAML, isso é definido durante a criação.
Para outros provedores, ele tem um valor predefinido (como google.com
ou
facebook.com
). É possível recuperar o providerId
das declarações do
usuário conectado.
Como importar usuários com vários fatores de autenticação
Se os usuários atuais tiverem números de telefone inscritos para usar com a autenticação multifator, será possível importá-los para o Identity Platform.
Os usuários de vários fatores precisam ter um e-mail verificado e um primeiro fator compatível. Até cinco fatores secundários são permitidos por usuário.
Você pode importar as seguintes propriedades de vários fatores:
Property | Tipo | Descrição |
---|---|---|
uid |
string |
Um ID exclusivo opcional do segundo fator inscrito. Se não for fornecido, um
uid aleatório será gerado automaticamente.
|
phoneNumber |
string | O número de telefone do segundo fator registrado. Esse número de telefone precisa ser compatível com E.164. |
displayName |
string | Um nome de exibição opcional. Isso será útil se um usuário tiver vários dois fatores registrados. |
enrollmentTime |
string | A data em que o segundo fator foi registrado, formatado como uma string UTC. Se não for fornecida, a data atual será usada. |
factorId |
string |
O segundo identificador de tipo de fator. Isso é sempre definido como phone .
|
O exemplo a seguir mostra como importar usuários de vários fatores:
Node.js
// Up to 1000 users can be imported at once.
const userImportRecords = [
{
uid: 'uid1',
email: 'user1@example.com',
emailVerified: true,
passwordHash: Buffer.from('passwordHash1'),
passwordSalt: Buffer.from('salt1'),
multiFactor: {
enrolledFactors: [
{
// Enrolled second factor uid is optional.
uid: 'uid1-unique-mfa-identifier1',
displayName: 'Personal phone',
phoneNumber: '+16505551234',
factorId: 'phone',
// Enrollment time is also optional.
enrollmentTime: 'Fri, 22 Sep 2017 01:49:58 GMT',
},
],
},
},
{
// User with multiple second factors.
uid: 'uid2',
email: 'user2@example.com',
emailVerified: true,
passwordHash: Buffer.from('passwordHash2'),
passwordSalt: Buffer.from('salt2'),
multiFactor: {
enrolledFactors: [
{
displayName: 'Work phone',
phoneNumber: '+16505550007',
factorId: 'phone',
},
{
displayName: 'Backup phone',
phoneNumber: '+16505550008',
factorId: 'phone',
},
],
},
},
{
// User with no second factor.
uid: 'uid3',
email: 'user3@example.com',
passwordHash: Buffer.from('passwordHash3'),
passwordSalt: Buffer.from('salt3'),
},
...
];
const userImportOptions = {
hash: {
algorithm: 'HMAC_SHA256',
key: Buffer.from('secretKey'),
},
};
admin.auth().importUsers(userImportRecords, userImportOptions)
.then((userImportResult) => {
// The number of successful imports is determined via: userImportResult.successCount.
// The number of failed imports is determined via: userImportResult.failureCount.
// To get the error details.
userImportResult.forEach(function(indexedError) {
// The corresponding user that failed to upload.
console.log(userImportRecords[indexedError.index].uid +' failed to import',
indexedError.error);
});
})
.catch((error) => {
// Some unrecoverable error occurred that prevented the operation from running.
});
use a interface de linha de comando;
Se os dados do usuário estiverem armazenados como JSON ou CSV, você poderá importá-los usando a ferramenta de linha de comando do Firebase:
firebase auth:import account_file \
--hash-algo=[HASH-ALGORITHM] \
--hash-key=[KEY] \
--salt-separator=[SALT-SEPARATOR] \
--rounds=[ROUNDS] \
--mem-cost=[MEM-COST] \
--parallelization=[PARALLELIZATION] \
--block-size=[BLOCK-SIZE] \
--dk-len=[DK-LEN] \
--hash-input-order=[HASH-INPUT-ORDER] \
Consulte a documentação de referência da interface de linha de comando para ver uma descrição completa de cada parâmetro.
A seguir
- Veja códigos de erro comuns que ocorrem na importação de usuários.
- Saiba como autenticar usuários no App Engine usando o Identity Platform.
- Saiba como Configurar declarações personalizadas com o Identity Platform.
- Leia sobre a API Admin Auth.