Para usar identidades externas com o Identity-Aware Proxy (IAP), seu app precisa de uma página de login. O IAP redirecionará os usuários para esta página para autenticação antes que eles acessem recursos seguros.
Neste artigo, você aprenderá como criar uma página de autenticação usando o FirebaseUI (em inglês), uma biblioteca JavaScript de código aberto. A FirebaseUI fornece elementos personalizáveis que ajudam a reduzir o código de texto clichê e processa os fluxos de login de usuários com uma ampla variedade de provedores de identidade.
Para começar mais rapidamente, deixe o IAP hospedar a IU para você. Isso permite que você teste identidades externas sem escrever códigos adicionais. Para cenários mais avançados, também é possível criar sua própria página de login do zero. Essa opção é mais complexa, mas oferece controle total sobre o fluxo de autenticação e a experiência do usuário.
Antes de começar
Ativar identidades externas e selecionar a opção Fornecerei minha própria IU durante a configuração.
Como instalar as bibliotecas
É necessário instalar as bibliotecas gcip-iap
, firebase
e firebaseui
. O módulo gcip-iap
abstrai as comunicações entre seu app, o IAP e o Identity Platform. As bibliotecas firebase
e firebaseui
fornecem os elementos fundamentais para a criação da IU de autenticação.
npm install firebase --save
npm install firebaseui --save
npm install gcip-iap --save
O módulo gcip-iap
não está disponível por meio da CDN.
Em seguida, você pode import
os módulos nos arquivos de origem. Use as importações corretas para sua versão do SDK:
gcip-iap v0.1.4 ou anterior
// Import firebase modules.
import * as firebase from "firebase/app";
import "firebase/auth";
// Import firebaseui module.
import * as firebaseui from 'firebaseui'
// Import gcip-iap module.
import * as ciap from 'gcip-iap';
gcip-iap v1.0.0 ou mais recente
A partir da versão v1.0.0, o gcip-iap
requer a dependência de peering firebase
v9 ou mais recente.
Se você estiver migrando para a gcip-iap
v1.0.0 ou mais recente, conclua as seguintes
ações:
- Atualize as versões
firebase
efirebaseui
no arquivopackage.json
para v9.6.0+ e v6.0.0+ respectivamente. - Atualize as instruções de importação
firebase
desta forma:
// Import firebase modules.
import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
// Import firebaseui module.
import * as firebaseui from 'firebaseui'
// Import gcip-iap module.
Nenhuma outra alteração de código é necessária.
Para outras opções de instalação, incluindo com o uso de versões localizadas das bibliotecas, consulte as instruções no GitHub (em inglês).
Como configurar seu aplicativo
O FirebaseUI usa um objeto de configuração que especifica os locatários e provedores a serem usados na autenticação. A configuração completa pode ser muito longa e ter esta aparência:
// The project configuration.
const configs = {
// Configuration for project identified by API key API_KEY1.
API_KEY1: {
authDomain: 'project-id1.firebaseapp.com',
// Decide whether to ask user for identifier to figure out
// what tenant to select or whether to present all the tenants to select from.
displayMode: 'optionFirst', // Or identifierFirst
// The terms of service URL and privacy policy URL for the page
// where the user select tenant or enter email for tenant/provider
// matching.
tosUrl: 'http://localhost/tos',
privacyPolicyUrl: 'http://localhost/privacypolicy',
callbacks: {
// The callback to trigger when the selection tenant page
// or enter email for tenant matching page is shown.
selectTenantUiShown: () => {
// Show title and additional display info.
},
// The callback to trigger when the sign-in page
// is shown.
signInUiShown: (tenantId) => {
// Show tenant title and additional display info.
},
beforeSignInSuccess: (user) => {
// Do additional processing on user before sign-in is
// complete.
return Promise.resolve(user);
}
},
tenants: {
// Tenant configuration for tenant ID tenantId1.
tenantId1: {
// Full label, display name, button color and icon URL of the
// tenant selection button. Only needed if you are
// using the option first option.
fullLabel: 'ACME Portal',
displayName: 'ACME',
buttonColor: '#2F2F2F',
iconUrl: '<icon-url-of-sign-in-button>',
// Sign-in providers enabled for tenantId1.
signInOptions: [
// Microsoft sign-in.
{
provider: 'microsoft.com',
providerName: 'Microsoft',
buttonColor: '#2F2F2F',
iconUrl: '<icon-url-of-sign-in-button>',
loginHintKey: 'login_hint'
},
// Email/password sign-in.
{
provider: 'password',
// Do not require display name on sign up.
requireDisplayName: false,
disableSignUp: {
// Disable user from signing up with email providers.
status: true,
adminEmail: 'admin@example.com',
helpLink: 'https://www.example.com/trouble_signing_in'
}
},
// SAML provider. (multiple SAML providers can be passed)
{
provider: 'saml.my-provider1',
providerName: 'SAML provider',
fullLabel: 'Employee Login',
buttonColor: '#4666FF',
iconUrl: 'https://www.example.com/photos/my_idp/saml.png'
},
],
// If there is only one sign-in provider eligible for the user,
// whether to show the provider selection page.
immediateFederatedRedirect: true,
signInFlow: 'redirect', // Or popup
// The terms of service URL and privacy policy URL for the sign-in page
// specific to each tenant.
tosUrl: 'http://localhost/tenant1/tos',
privacyPolicyUrl: 'http://localhost/tenant1/privacypolicy'
},
// Tenant configuration for tenant ID tenantId2.
tenantId2: {
fullLabel: 'OCP Portal',
displayName: 'OCP',
buttonColor: '#2F2F2F',
iconUrl: '<icon-url-of-sign-in-button>',
// Tenant2 supports a SAML, OIDC and Email/password sign-in.
signInOptions: [
// Email/password sign-in.
{
provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
// Do not require display name on sign up.
requireDisplayName: false
},
// SAML provider. (multiple SAML providers can be passed)
{
provider: 'saml.my-provider2',
providerName: 'SAML provider',
fullLabel: 'Contractor Portal',
buttonColor: '#4666FF',
iconUrl: 'https://www.example.com/photos/my_idp/saml.png'
},
// OIDC provider. (multiple OIDC providers can be passed)
{
provider: 'oidc.my-provider1',
providerName: 'OIDC provider',
buttonColor: '#4666FF',
iconUrl: 'https://www.example.com/photos/my_idp/oidc.png'
},
],
},
// Tenant configuration for tenant ID tenantId3.
tenantId3: {
fullLabel: 'Tenant3 Portal',
displayName: 'Tenant3',
buttonColor: '#007bff',
iconUrl: '<icon-url-of-sign-in-button>',
// Tenant3 supports a Google and Email/password sign-in.
signInOptions: [
// Email/password sign-in.
{
provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
// Do not require display name on sign up.
requireDisplayName: false
},
// Google provider.
{
provider: 'google.com',
scopes: ['scope1', 'scope2', 'https://example.com/scope3'],
loginHintKey: 'login_hint',
customParameters: {
prompt: 'consent',
},
},
],
// Sets the adminRestrictedOperation configuration for providers
// including federated, email/password, email link and phone number.
adminRestrictedOperation: {
status: true,
adminEmail: 'admin@example.com',
helpLink: 'https://www.example.com/trouble_signing_in'
}
},
},
},
};
Veja nas seções a seguir as orientações sobre como configurar alguns dos campos específicos do IAP. Para exemplos sobre como definir outros campos, consulte o snippet de código acima ou a documentação do FirebaseUI no GitHub (em inglês).
Como definir a chave de API
Uma configuração típica começa com a chave de API do projeto:
// The project configuration.
const configs = {
// Configuration for API_KEY.
API_KEY: {
// Config goes here
}
}
Na maioria dos casos, você só precisa especificar uma única chave de API. No entanto, se você quiser usar o mesmo URL de autenticação em vários projetos, inclua várias chaves de API:
const configs = {
API_KEY1: {
// Config goes here
},
API_KEY2: {
// Config goes here
},
}
Como saber o domínio de autenticação
Defina o campo authdomain
como o domínio provisionado para facilitar o login federado. É possível recuperar esse campo na
Página do Identity Platform no console do Google Cloud.
Como especificar IDs de locatários
Para fazer a configuração, é necessário informar uma lista de locatários e provedores que serão utilizados na autenticação dos usuários.
Cada locatário é identificado por um ID. Se você adotou a autenticação para envolvidos no projeto (sem locatários), use o identificador especial "_
" como chave de API. Por exemplo:
const configs = {
// Configuration for project identified by API key API_KEY1.
API_KEY1: {
tenants: {
// Project-level IdPs flow.
_: {
// Tenant config goes here
},
// Single tenant flow.
1036546636501: {
// Tenant config goes here
}
}
}
}
Também é possível especificar uma configuração de locatário com caractere curinga usando o operador "*
".
Esse locatário servirá como substituto se nenhum ID correspondente for encontrado.
Como configurar provedores de locatários
Cada locatário tem os próprios provedores, que são especificados no campo signInOptions
:
tenantId1: {
signInOptions: [
// Options go here
]
}
Consulte Como configurar provedores de login (em inglês) na documentação do FirebaseUI para mais informações.
Além das etapas descritas na documentação do FirebaseUI, existem vários campos específicos para o IAP que dependem do modo de seleção de locatário escolhido. Para mais informações sobre esses campos, consulte a próxima seção.
Como escolher um modo de seleção de locatário
Os usuários podem selecionar um locatário de duas maneiras: modo primeiro as opções ou modo primeiro o identificador.
No modo das opções, o usuário começa selecionando um locatário em uma lista e depois digita o nome de usuário e a senha. No modo do identificador, o usuário primeiro insere o e-mail. Então, o sistema seleciona automaticamente o primeiro locatário com um provedor de identidade correspondente ao domínio do e-mail.
Para usar o modo das opções, defina displayMode
como optionFirst
. Em seguida, você precisará fornecer as informações de configuração para o botão de cada locatário, incluindo displayName
, buttonColor
e iconUrl
. Um fullLabel
opcional também pode ser
fornecido para substituir todo o rótulo do botão, em vez de apenas
o nome de exibição.
Veja a seguir um exemplo de locatário configurado para usar o modo das opções:
tenantId1: {
fullLabel: 'ACME Portal',
displayName: 'ACME',
buttonColor: '#2F2F2F',
iconUrl: '<icon-url-of-sign-in-button>',
// ...
Para usar o modo do identificador, é necessário que em cada opção de login haja um campo hd
especificado, indicando o domínio aceito. Esse valor pode ser uma regex, como /@example\.com$/
, ou a string do domínio, como example.com
.
O código abaixo mostra um locatário configurado para usar o modo do identificador:
tenantId1: {
signInOptions: [
// Email/password sign-in.
{
hd: 'acme.com', // using regex: /@acme\.com$/
// ...
},
Como ativar o redirecionamento imediato
Se seu app aceitar um único provedor de identidade, definir immediateFederatedRedirect
como true
fará com que a IU de login seja ignorada e redirecionará o usuário diretamente para o provedor.
Como configurar callbacks
O objeto de configuração contém um conjunto de callbacks invocados em vários pontos durante o fluxo de autenticação. Com isso, é possível personalizar ainda mais a IU. Os hooks a seguir estão disponíveis:
selectTenantUiShown() |
Acionado quando a IU para selecionar um locatário é exibida. Use-o se você quiser modificar a IU com um título ou tema personalizado. |
signInUiShown(tenantId) |
Acionado quando um locatário é selecionado e é exibida a IU para que o usuário insira as credenciais. Use-o se você quiser modificar a IU com um título ou tema personalizado. |
beforeSignInSuccess(user) |
Acionado antes do término do login. Use-o para modificar um usuário conectado antes de redirecionar para o recurso do IAP. |
O exemplo de código a seguir mostra como implementar esses callbacks:
callbacks: {
selectTenantUiShown: () => {
// Show info of the IAP resource.
showUiTitle(
'Select your employer to access your Health Benefits');
},
signInUiShown: (tenantId) => {
// Show tenant title and additional display info.
const tenantName = getTenantNameFromId(tenantId);
showUiTitle(`Sign in to access your ${tenantName} Health Benefits`);
},
beforeSignInSuccess: (user) => {
// Do additional processing on user before sign-in is
// complete.
// For example update the user profile.
return user.updateProfile({
photoURL: 'https://example.com/profile/1234/photo.png',
}).then(function() {
// To reflect updated photoURL in the ID token, force token
// refresh.
return user.getIdToken(true);
}).then(function() {
return user;
});
}
}
Como inicializar a biblioteca
Depois de criar um objeto de configuração, siga estas etapas para inicializar a biblioteca na sua página de autenticação:
Crie o contêiner HTML em que a IU será renderizada.
<!DOCTYPE html> <html> <head>...</head> <body> <!-- The surrounding HTML is left untouched by FirebaseUI. Your app may use that space for branding, controls and other customizations.--> <h1>Welcome to My Awesome App</h1> <div id="firebaseui-auth-container"></div> </body> </html>
Crie uma instância
FirebaseUiHandler
a ser renderizada no contêiner HTML e transmita para ela o elementoconfig
que você criou.const configs = { // ... } const handler = new firebaseui.auth.FirebaseUiHandler( '#firebaseui-auth-container', configs);
Crie uma nova instância
Authentication
, transmita o gerenciador para ela e chamestart()
.const ciapInstance = new ciap.Authentication(handler); ciapInstance.start();
Implante seu aplicativo e navegue até a página de autenticação. Você verá uma IU de login contendo seus locatários e provedores.
A seguir
- Saiba como acessar recursos que não são do Google de maneira programática.
- Saiba como gerenciar sessões.
- Entenda melhor como as identidades externas funcionam com o IAP.