Autenticar usuários com o Azure Active Directory B2C

O Azure Active Directory B2C fornece gerenciamento de identidade na nuvem para aplicativos móveis e Web voltados para o consumidor. Este artigo mostra como usar o Azure Active Directory B2C para integrar o gerenciamento de identidades em um aplicativo móvel com a Biblioteca de Autenticação da Microsoft.

Visão geral

O Azure Active Directory B2C (ADB2C) é um serviço de gerenciamento de identidades para aplicativos voltados para o consumidor. Ele permite que os usuários entrem em seu aplicativo usando suas contas sociais existentes ou credenciais personalizadas, como email ou nome de usuário e senha. As contas de credenciais personalizadas são chamadas de contas locais .

O processo para integrar o serviço de gerenciamento de identidades B2C do Active Directory do Azure em um aplicativo móvel é o seguinte:

  1. Crie um locatário do Azure Active Directory B2C.
  2. Registre seu aplicativo móvel com o locatário B2C do Active Directory do Azure.
  3. Crie políticas para inscrição e entrada e esqueceu os fluxos de usuário de senha.
  4. Use a Biblioteca de Autenticação da Microsoft (MSAL) para iniciar um fluxo de trabalho de autenticação com seu locatário B2C do Active Directory do Azure.

Observação

Se você não tiver uma assinatura do Azure, crie uma conta gratuita antes de começar.

O Azure Active Directory B2C oferece suporte a vários provedores de identidade, incluindo Microsoft, GitHub, Facebook, Twitter e muito mais. Para obter mais informações sobre os recursos B2C do Active Directory do Azure, consulte Documentação do Azure Active Directory B2C.

A Biblioteca de Autenticação da Microsoft oferece suporte a várias arquiteturas e plataformas de aplicativos. Para obter informações sobre os recursos do MSAL, consulte Biblioteca de autenticação da Microsoft no GitHub.

Configurar um locatário B2C do Active Directory do Azure

Para executar o projeto de exemplo, você deve criar um locatário B2C do Active Directory do Azure. Para obter mais informações, consulte Criar um locatário B2C do Active Directory do Azure no portal do Azure.

Depois de criar um locatário, você precisará do nome do locatário e da ID do locatário para configurar o aplicativo móvel. A ID e o nome do locatário são definidos pelo domínio gerado quando você criou a URL do locatário. Se a URL do locatário gerada for https://contoso20190410tenant.onmicrosoft.com/ a ID do locatário e contoso20190410tenant.onmicrosoft.com o nome do locatário for contoso20190410tenant. Localize o domínio do locatário no portal do Azure clicando no filtro de diretório e assinatura no menu superior. A captura de tela a seguir mostra o botão de filtro de assinatura e diretório do Azure e o domínio do locatário:

Nome do locatário no modo de exibição de filtro de assinatura e diretório do Azure

No projeto de exemplo, edite o arquivo Constants.cs para definir os tenantName campos e tenantId . O código a seguir mostra como esses valores devem ser definidos se o domínio do locatário for https://contoso20190410tenant.onmicrosoft.com/, substitua esses valores por valores do seu portal:

public static class Constants
{
    static readonly string tenantName = "contoso20190410tenant";
    static readonly string tenantId = "contoso20190410tenant.onmicrosoft.com";
    ...
}

Registrar seu aplicativo móvel com o Azure Active Directory B2C

Um aplicativo móvel deve ser registrado com o locatário para que ele possa se conectar e autenticar usuários. O processo de registro atribui uma ID de Aplicativo exclusiva ao aplicativo e uma URL de Redirecionamento que direciona as respostas de volta ao aplicativo após a autenticação. Para obter mais informações, consulte Azure Active Directory B2C: Registrar seu aplicativo. Você precisará saber a ID do aplicativo atribuída ao seu aplicativo, que é listada após o nome do aplicativo na exibição de propriedades. A captura de tela a seguir mostra onde encontrar a ID do aplicativo:

ID do aplicativo no modo de exibição de propriedades do aplicativo do Azure

A Biblioteca de Autenticação da Microsoft espera que a URL de redirecionamento do seu aplicativo seja sua ID do aplicativo prefixada com o texto "msal" e seguida por um ponto de extremidade chamado "auth". Se o ID do aplicativo for "1234abcd", a URL completa deverá ser msal1234abcd://auth. Verifique se o aplicativo habilitou a configuração do cliente nativo e crie um URI de redirecionamento personalizado usando a ID do aplicativo, conforme mostrado na captura de tela a seguir:

URI de redirecionamento personalizado no modo de exibição de propriedades do aplicativo do Azure

A URL será usada posteriormente no Android ApplicationManifest.xml e no iOS Info.plist.

No projeto de exemplo, edite o arquivo Constants.cs para definir o clientId campo para sua ID do aplicativo. O código a seguir mostra como esse valor deve ser definido se sua ID do aplicativo for 1234abcd:

public static class Constants
{
    static readonly string tenantName = "contoso20190410tenant";
    static readonly string tenantId = "contoso20190410tenant.onmicrosoft.com";
    static readonly string clientId = "1234abcd";
    ...
}

Criar políticas de inscrição e entrada e esqueceu as políticas de senha

Uma política é uma experiência pela qual os usuários passam para concluir uma tarefa, como criar uma conta ou redefinir uma senha. Uma política também especifica o conteúdo dos tokens que o aplicativo recebe quando o usuário retorna da experiência. Você deve configurar políticas para inscrição e entrada na conta e redefinir a senha. O Azure tem políticas internas que simplificam a criação de políticas comuns. Para obter mais informações, consulte Azure Active Directory B2C: políticas internas.

Depois de concluir a configuração da política, você deve ter duas políticas no modo de exibição Fluxos de usuário (políticas) no portal do Azure. A captura de tela a seguir demonstra duas políticas configuradas no portal do Azure:

Duas políticas configuradas no modo de exibição Fluxos de usuário (políticas) do Azure

No projeto de exemplo, edite o arquivo Constants.cs para definir os policySignin campos e policyPassword para refletir os nomes escolhidos durante a configuração da política:

public static class Constants
{
    static readonly string tenantName = "contoso20190410tenant";
    static readonly string tenantId = "contoso20190410tenant.onmicrosoft.com";
    static readonly string clientId = "1234abcd";
    static readonly string policySignin = "B2C_1_signupsignin1";
    static readonly string policyPassword = "B2C_1_passwordreset";
    ...
}

Usar a Microsoft Authentication Library (MSAL) para autenticação

O pacote NuGet da Biblioteca de Autenticação da Microsoft (MSAL) deve ser adicionado ao projeto compartilhado, ao .NET Standard e aos projetos de plataforma em uma Xamarin.Forms solução. MSAL inclui uma PublicClientApplicationBuilder classe que constrói um objeto aderente à IPublicClientApplication interface. MSAL utiliza With cláusulas para fornecer parâmetros adicionais para o construtor e métodos de autenticação.

No projeto de exemplo, o code-behind para App.xaml define propriedades estáticas nomeadas AuthenticationClient e UIParent, e instancia o AuthenticationClient objeto no construtor. A WithIosKeychainSecurityGroup cláusula fornece um nome de grupo de segurança para aplicativos iOS. A WithB2CAuthority cláusula fornece a Autoridade padrão, ou política, que será usada para autenticar usuários. A WithRedirectUri cláusula informa à instância dos Hubs de Notificação do Azure qual URI de redirecionamento usar se vários URIs forem especificados. O exemplo a seguir demonstra como instanciar o PublicClientApplication:

public partial class App : Application
{
    public static IPublicClientApplication AuthenticationClient { get; private set; }

    public static object UIParent { get; set; } = null;

    public App()
    {
        InitializeComponent();

        AuthenticationClient = PublicClientApplicationBuilder.Create(Constants.ClientId)
            .WithIosKeychainSecurityGroup(Constants.IosKeychainSecurityGroups)
            .WithB2CAuthority(Constants.AuthoritySignin)
            .WithRedirectUri($"msal{Constants.ClientId}://auth")
            .Build();

        MainPage = new NavigationPage(new LoginPage());
    }

    ...

Observação

Se sua instância dos Hubs de Notificação do Azure tiver apenas um URI de Redirecionamento definido, a AuthenticationClient instância poderá funcionar sem especificar o URI de Redirecionamento com a WithRedirectUri cláusula. No entanto, você sempre deve especificar esse valor caso sua configuração do Azure se expanda para oferecer suporte a outros clientes ou métodos de autenticação.

O OnAppearing manipulador de eventos no LoginPage.xaml.cs código atrás de chamadas AcquireTokenSilentAsync para atualizar o token de autenticação para usuários que fizeram logon antes. O processo de autenticação redireciona para o LogoutPage se bem-sucedido e não faz nada em caso de falha. O exemplo a seguir mostra o processo de reautenticação silenciosa em OnAppearing:

public partial class LoginPage : ContentPage
{
    ...

    protected override async void OnAppearing()
    {
        try
        {
            // Look for existing account
            IEnumerable<IAccount> accounts = await App.AuthenticationClient.GetAccountsAsync();

            AuthenticationResult result = await App.AuthenticationClient
                .AcquireTokenSilent(Constants.Scopes, accounts.FirstOrDefault())
                .ExecuteAsync();

            await Navigation.PushAsync(new LogoutPage(result));
        }
        catch
        {
            // Do nothing - the user isn't logged in
        }
        base.OnAppearing();
    }

    ...
}

O OnLoginButtonClicked manipulador de eventos (acionado quando o botão Login é clicado) chama AcquireTokenAsync. A biblioteca MSAL abre automaticamente o navegador do dispositivo móvel e navega até a página de logon. A URL de entrada, chamada de Autoridade, é uma combinação do nome do locatário e das políticas definidas no arquivo Constants.cs . Se o usuário escolher a opção de senha esquecida, ele será retornado ao aplicativo com uma exceção, o que inicia a experiência de senha esquecida. O exemplo a seguir mostra o processo de autenticação:

public partial class LoginPage : ContentPage
{
    ...

    async void OnLoginButtonClicked(object sender, EventArgs e)
    {
        AuthenticationResult result;
        try
        {
            result = await App.AuthenticationClient
                .AcquireTokenInteractive(Constants.Scopes)
                .WithPrompt(Prompt.SelectAccount)
                .WithParentActivityOrWindow(App.UIParent)
                .ExecuteAsync();

            await Navigation.PushAsync(new LogoutPage(result));
        }
        catch (MsalException ex)
        {
            if (ex.Message != null && ex.Message.Contains("AADB2C90118"))
            {
                result = await OnForgotPassword();
                await Navigation.PushAsync(new LogoutPage(result));
            }
            else if (ex.ErrorCode != "authentication_canceled")
            {
                await DisplayAlert("An error has occurred", "Exception message: " + ex.Message, "Dismiss");
            }
        }
    }

    ...
}

O OnForgotPassword método é semelhante ao processo de entrada, mas implementa uma política personalizada. OnForgotPasswordusa uma sobrecarga diferente de AcquireTokenAsync, o que permite que você forneça uma Autoridade específica. O exemplo a seguir mostra como fornecer uma Autoridade personalizada ao adquirir um token:

public partial class LoginPage : ContentPage
{
    ...
    async Task<AuthenticationResult> OnForgotPassword()
    {
        try
        {
            return await App.AuthenticationClient
                .AcquireTokenInteractive(Constants.Scopes)
                .WithPrompt(Prompt.SelectAccount)
                .WithParentActivityOrWindow(App.UIParent)
                .WithB2CAuthority(Constants.AuthorityPasswordReset)
                .ExecuteAsync();
        }
        catch (MsalException)
        {
            // Do nothing - ErrorCode will be displayed in OnLoginButtonClicked
            return null;
        }
    }
}

A parte final da autenticação é o processo de logout. O OnLogoutButtonClicked método é chamado quando o usuário pressiona o botão de logout. Ele percorre todas as contas e garante que seus tokens foram invalidados. O exemplo abaixo demonstra a implementação de logout:

public partial class LogoutPage : ContentPage
{
    ...
    async void OnLogoutButtonClicked(object sender, EventArgs e)
    {
        IEnumerable<IAccount> accounts = await App.AuthenticationClient.GetAccountsAsync();

        while (accounts.Any())
        {
            await App.AuthenticationClient.RemoveAsync(accounts.First());
            accounts = await App.AuthenticationClient.GetAccountsAsync();
        }

        await Navigation.PopAsync();
    }
}

iOS

No iOS, o esquema de URL personalizado que foi registrado no Azure Active Directory B2C deve ser registrado no Info.plist. A MSAL espera que o esquema de URL siga um padrão específico, descrito anteriormente em Registrar seu aplicativo móvel com o Azure Active Directory B2C. A captura de tela a seguir mostra o esquema de URL personalizado no Info.plist.

O MSAL também requer Direitos de Chaveiro no iOS, registrados no Entitilements.plist, conforme mostrado na captura de tela a seguir:

Quando o Azure Active Directory B2C conclui a solicitação de autorização, ele redireciona para a URL de redirecionamento registrada. O esquema de URL personalizado resulta em iOS iniciando o aplicativo móvel e passando a URL como um parâmetro de inicialização, onde é processado pela OpenUrl substituição da classe do aplicativo AppDelegate e retorna o controle da experiência para MSAL. A OpenUrl implementação é mostrada no exemplo de código a seguir:

using Microsoft.Identity.Client;

namespace TodoAzure.iOS
{
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {
        ...
        public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
        {
            AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(url);
            return base.OpenUrl(app, url, options);
        }
    }
}

Android

No Android, o esquema de URL personalizado que foi registrado no Azure Active Directory B2C deve ser registrado no AndroidManifest.xml. A MSAL espera que o esquema de URL siga um padrão específico, descrito anteriormente em Registrar seu aplicativo móvel com o Azure Active Directory B2C. O exemplo a seguir mostra o esquema de URL personalizado no AndroidManifest.xml.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.xamarin.adb2cauthorization">
  <uses-sdk android:minSdkVersion="15" />
  <application android:label="ADB2CAuthorization">
    <activity android:name="microsoft.identity.client.BrowserTabActivity">
      <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <!-- example -->
        <!-- <data android:scheme="msalaaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" android:host="auth" /> -->
        <data android:scheme="INSERT_URI_SCHEME_HERE" android:host="auth" />
      </intent-filter>
    </activity>"
  </application>
</manifest>

A MainActivity classe deve ser modificada para fornecer o UIParent objeto ao aplicativo durante a OnCreate chamada. Quando o Azure Active Directory B2C conclui a solicitação de autorização, ele redireciona para o esquema de URL registrado do AndroidManifest.xml. O esquema de URI registrado resulta no Android chamando o OnActivityResult método com a URL como um parâmetro de inicialização, onde ele é processado SetAuthenticationContinuationEventArgs pelo método.

public class MainActivity : FormsAppCompatActivity
{
    protected override void OnCreate(Bundle bundle)
    {
        TabLayoutResource = Resource.Layout.Tabbar;
        ToolbarResource = Resource.Layout.Toolbar;

        base.OnCreate(bundle);

        Forms.Init(this, bundle);
        LoadApplication(new App());
        App.UIParent = this;
    }

    protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
    {
        base.OnActivityResult(requestCode, resultCode, data);
        AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(requestCode, resultCode, data);
    }
}

Plataforma Universal do Windows

Nenhuma configuração adicional é necessária para usar o MSAL na Plataforma Universal do Windows

Executar o projeto

Execute o aplicativo em um dispositivo virtual ou físico. Tocar no botão Login deve abrir o navegador e navegar até uma página onde você pode entrar ou criar uma conta. Depois de concluir o processo de login, você deve retornar à página de logout do aplicativo. A captura de tela a seguir mostra a tela de login do usuário em execução no Android e iOS: