Requisitos de configuração e dicas de solução de problemas para o Xamarin Android com MSAL.NET

Há várias alterações de configuração que você precisa fazer no seu código ao usar o Xamarin Android com a Biblioteca de Autenticação da Microsoft para .NET (MSAL.NET). As seções a seguir descrevem as modificações necessárias, seguidas por uma seção de solução de problemas para ajudar a evitar alguns dos problemas mais comuns.

Definir a atividade pai

No Xamarin Android, defina a atividade pai para que o token seja retornado após a interação:

var authResult = AcquireTokenInteractive(scopes)
 .WithParentActivityOrWindow(parentActivity)
 .ExecuteAsync();

No MSAL.NET 4.2 e posteriores, você também pode definir essa funcionalidade no nível de PublicClientApplication. Para fazer isso, use um retorno de chamada:

// Requires MSAL.NET 4.2 or later
var pca = PublicClientApplicationBuilder
  .Create("<your-client-id-here>")
  .WithParentActivityOrWindow(() => parentActivity)
  .Build();

Se usar CurrentActivityPlugin, o código de construtor PublicClientApplication deve se parecer com este snippet de código:

// Requires MSAL.NET 4.2 or later
var pca = PublicClientApplicationBuilder
  .Create("<your-client-id-here>")
  .WithParentActivityOrWindow(() => CrossCurrentActivity.Current)
  .Build();

Verifique se o controle retorna ao MSAL

Quando a parte interativa do fluxo de autenticação terminar, retorne o controle ao MSAL substituindo Activity.Método OnActivityResult().

Em sua substituição, chame o método AuthenticationContinuationHelper. do MSAL.NETSetAuthenticationContinuationEventArgs()Para retornar o controle ao MSAL no final da parte interativa do fluxo de autenticação.

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

    // Return control to MSAL
    AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(requestCode,
                                                                            resultCode,
                                                                            data);
}

Atualizar o manifesto do Android para o suporte do sistema de WebView

Para dar suporte ao sistema WebView, o arquivo AndroidManifest.xml deve conter os seguintes valores:

<activity android:name="microsoft.identity.client.BrowserTabActivity" android:configChanges="orientation|screenSize" android:exported="true">
  <intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="msal{Client Id}" android:host="auth" />
  </intent-filter>
</activity>

O valor android:scheme é criado a partir do URI de redirecionamento configurado no portal do aplicativo. Por exemplo, se o URI de redirecionamento for msal00001111-aaaa-2222-bbbb-3333cccc4444://auth, a entrada android:scheme no manifesto seria semelhante a este exemplo:

<data android:scheme="msal00001111-aaaa-2222-bbbb-3333cccc4444" android:host="auth" />

Como alternativa, crie a atividade no código em vez de editar manualmente AndroidManifest.xml. Para criar a atividade no código, crie primeiro uma classe que inclua os atributo Activity e IntentFilter.

Veja um exemplo de uma classe que representa os valores do arquivo XML:

  [Activity(Exported = true)]
  [IntentFilter(new[] { Intent.ActionView },
        Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault },
        DataHost = "auth",
        DataScheme = "msal{client_id}")]
  public class MsalActivity : BrowserTabActivity
  {
  }

Usar o WebView do sistema na autenticação agenciada

Para usar o WebView do sistema como um fallback para autenticação interativa quando você configurou seu aplicativo para usar a autenticação orientada e o dispositivo não tem um agente instalado, habilite o MSAL para capturar a resposta de autenticação usando o URI de redirecionamento do agente. O MSAL tentará autenticar usando o sistema de WebView padrão no dispositivo quando detectar que o agente está indisponível. Usando esse padrão, ele falhará porque o URI de redirecionamento está configurado para usar um agente e o WebView do sistema não sabe como usá-lo para retornar ao MSAL. Para resolver isso, crie um filtro de intenção usando o URI de redirecionamento do agente configurado anteriormente. Para adicionar o filtro de intenção, mude o manifesto do aplicativo como neste exemplo:

<!--Intent filter to capture System WebView or Authenticator calling back to our app after sign-in-->
<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" />
          <data android:scheme="msauth"
              android:host="Enter_the_Package_Name"
              android:path="/Enter_the_Signature_Hash" />
    </intent-filter>
</activity>

Substitua o nome do pacote que você registrou no portal do Azure pelo valor android:host=. Substitua o hash de chave que você registrou no portal do Azure pelo valor android:path=. O hash de assinatura não deve ser codificado por URL. Verifique se uma barra à esquerda (/) é exibida no início do hash de assinatura.

Manifesto Xamarin.Forms 4.3.x

O Xamarin. Forms 4.3.x gera código que define o atributo package como com.companyname.{appName} em AndroidManifest.xml. Se você usar DataScheme como msal{client_id}, talvez queira mudar o valor para corresponder ao valor do namespace MainActivity.cs.

Suporte para Android 11

Para usar o navegador do sistema e a autenticação orientada no Android 11, você precisa primeiro declarar esses pacotes para que eles fiquem visíveis para o aplicativo. Os aplicativos destinados ao Android 10 (API 29) e anteriores podem consultar o sistema operacional para receber uma lista de pacotes disponíveis no dispositivo em um determinado momento. Para permitir privacidade e segurança, o Android 11 reduz a visibilidade do pacote a uma lista padrão de pacotes do sistema operacional e aos pacotes especificados no arquivo AndroidManifest.xml do aplicativo.

Para permitir que o aplicativo seja autenticado usando o navegador do sistema e o agente, adicione a seguinte seção a AndroidManifest.xml:

<!-- Required for API Level 30 to make sure the app can detect browsers and other apps where communication is needed.-->
<!--https://developer.android.com/training/basics/intents/package-visibility-use-cases-->
<queries>
  <package android:name="com.azure.authenticator" />
  <package android:name="{Package Name}" />
  <package android:name="com.microsoft.windowsintune.companyportal" />
  <!-- Required for API Level 30 to make sure the app detect browsers
      (that don't support custom tabs) -->
  <intent>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="https" />
  </intent>
  <!-- Required for API Level 30 to make sure the app can detect browsers that support custom tabs -->
  <!-- https://developers.google.com/web/updates/2020/07/custom-tabs-android-11#detecting_browsers_that_support_custom_tabs -->
  <intent>
    <action android:name="android.support.customtabs.action.CustomTabsService" />
  </intent>
</queries>

Substitua {Package Name} pelo nome do pacote de aplicativos.

Seu manifesto atualizado, que agora inclui suporte para o navegador do sistema e a autenticação orientada, deve ser semelhante a este exemplo:

<?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.companyname.XamarinDev">
    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <application android:theme="@android:style/Theme.NoTitleBar">
        <activity android:name="microsoft.identity.client.BrowserTabActivity" android:configChanges="orientation|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="msal00001111-aaaa-2222-bbbb-3333cccc4444" android:host="auth" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="msauth" android:host="com.companyname.XamarinDev" android:path="/Fc4l/5I4mMvLnF+l+XopDuQ2gEM=" />
            </intent-filter>
        </activity>
    </application>
    <!-- Required for API Level 30 to make sure we can detect browsers and other apps we want to
     be able to talk to.-->
    <!--https://developer.android.com/training/basics/intents/package-visibility-use-cases-->
    <queries>
        <package android:name="com.azure.authenticator" />
        <package android:name="com.companyname.xamarindev" />
        <package android:name="com.microsoft.windowsintune.companyportal" />
        <!-- Required for API Level 30 to make sure we can detect browsers
        (that don't support custom tabs) -->
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="https" />
        </intent>
        <!-- Required for API Level 30 to make sure we can detect browsers that support custom tabs -->
        <!-- https://developers.google.com/web/updates/2020/07/custom-tabs-android-11#detecting_browsers_that_support_custom_tabs -->
        <intent>
            <action android:name="android.support.customtabs.action.CustomTabsService" />
        </intent>
    </queries>
</manifest>

Usar a exibição da Web inserida (opcional)

Por padrão, MSAL.NET o navegador da Web do sistema. Este navegador permite obter SSO (logon único) usando aplicativos Web e outros aplicativos. Em alguns casos raros, talvez você queira que o seu sistema use uma exibição da Web inserida.

Este exemplo de código mostra como configurar uma exibição da Web inserida:

bool useEmbeddedWebView = !app.IsSystemWebViewAvailable;

var authResult = AcquireTokenInteractive(scopes)
 .WithParentActivityOrWindow(parentActivity)
 .WithEmbeddedWebView(useEmbeddedWebView)
 .ExecuteAsync();

Para obter mais informações, confira Usar navegadores da Web para MSAL.NET e Considerações sobre o navegador do sistema Xamarin Android.

Solução de problemas

Dicas gerais

  • Atualize o pacote NuGet do MSAL.NET para a versão mais recente do MSAL.NET.
  • Verifique se o Xamarin.Forms está na versão mais recente.
  • Verifique se Xamarin.Android.Support.v4 está na versão mais recente.
  • Verifique se todos os pacotes Xamarin.Android.Support têm como destino a versão mais recente.
  • Limpe ou recompile o aplicativo.
  • No Visual Studio, tente definir o número máximo de compilações de projetos paralelas como 1. Para fazer isso, selecione Opções>Projetos e soluções>Compilar e executar>Número máximo de compilações de projetos paralelos.
  • Se estiver criando a partir da linha de comando e o comando usar /m, tente remover esse elemento do comando.

Erro: o nome AuthenticationContinuationHelper não existe no contexto atual

Se um erro indicar que AuthenticationContinuationHelper não existe no contexto atual, o Visual Studio poderá ter atualizado incorretamente o arquivo Android.csproj*. Às vezes, o caminho do arquivo no elemento <HintPath> contém incorretamente netstandard13 em vez de monoandroid90.

Este exemplo contém um caminho de arquivo correto:

<Reference Include="Microsoft.Identity.Client, Version=3.0.4.0, Culture=neutral, PublicKeyToken=0a613f4dd989e8ae,
           processorArchitecture=MSIL">
  <HintPath>..\..\packages\Microsoft.Identity.Client.3.0.4-preview\lib\monoandroid90\Microsoft.Identity.Client.dll</HintPath>
</Reference>

Próximas etapas

Para obter mais informações, confira o exemplo de um aplicativo móvel Xamarin que usa a plataforma de identidade da Microsoft. A tabela a seguir resume as informações relevantes no arquivo README.

Amostra Plataforma Descrição
https://github.com/Azure-Samples/active-directory-xamarin-native-v2 Xamarin.iOS, Android, UWP Um aplicativo móvel Xamarin que mostra como usar o MSAL.NET para autenticar contas corporativas ou de estudante e contas Microsoft pessoais na plataforma de identidade da Microsoft e acessar a API do Microsoft Graph com o token resultante.
Diagrama do fluxo de autenticação