Condividi tramite


Aggiungere l'autenticazione all'app Xamarin.Forms

Nota

Questo prodotto viene ritirato. Per una sostituzione dei progetti che usano .NET 8 o versione successiva, vedere la libreria datasync di Community Toolkit.

In questa esercitazione si aggiunge l'autenticazione Microsoft all'app usando Microsoft Entra ID. Prima di completare questa esercitazione, assicurarsi di aver creato il progetto e distribuito il back-end.

Nota

Poiché l'app iOS richiede l'accesso keychain, è necessario configurare un profilo di provisioning iOS. Un profilo di provisioning richiede un dispositivo iOS reale o un account Apple Developer a pagamento (se si usa il simulatore). È possibile ignorare questa esercitazione e passare all'aggiunta di accesso offline all'app se non è possibile usare l'autenticazione a causa di questa restrizione.

Mancia

Anche se si usa Microsoft Entra ID per l'autenticazione, è possibile usare qualsiasi libreria di autenticazione desiderata con App per dispositivi mobili di Azure.

Aggiungere l'autenticazione al servizio back-end

Il servizio back-end è un servizio standard ASP.NET 6. Qualsiasi esercitazione che illustra come abilitare l'autenticazione per un servizio ASP.NET 6 funziona con App per dispositivi mobili di Azure.

Per abilitare l'autenticazione di Microsoft Entra per il servizio back-end, è necessario:

  • Registrare un'applicazione con Microsoft Entra ID.
  • Aggiungere il controllo dell'autenticazione al progetto back-end ASP.NET 6.

Registrare l'applicazione

Prima di tutto, registrare l'API Web nel tenant di Microsoft Entra e aggiungere un ambito seguendo questa procedura:

  1. Accedere al portale di Azure .

  2. Se si ha accesso a più tenant, usare il filtro Directory e sottoscrizioni nel menu in alto per passare al tenant in cui si vuole registrare l'applicazione.

  3. Cercare e selezionare ID Microsoft Entra.

  4. In Gestisciselezionare Registrazioni app>Nuova registrazione.

    • Nome: immettere un nome per l'applicazione; ad esempio, Guida introduttiva a TodoApp. Gli utenti dell'app vedranno questo nome. È possibile modificarlo in un secondo momento.
    • Tipi di account supportati: account in qualsiasi directory organizzativa (qualsiasi directory Microsoft Entra - Multi-tenant) e account Microsoft personali (ad esempio Skype, Xbox)
  5. Selezionare Registra.

  6. In Gestisciselezionare Esporre un'API>Aggiungere un ambito.

  7. Per URI ID applicazione, accettare l'impostazione predefinita selezionando Salva e continua.

  8. Immettere i dettagli seguenti:

    • nome ambito: access_as_user
    • Chi può fornire il consenso?: amministratori e utenti
    • nome visualizzato del consenso amministratore: Access TodoApp
    • Descrizione del consenso amministratore : Allows the app to access TodoApp as the signed-in user.
    • Nome visualizzato del consenso utente: Access TodoApp
    • Descrizione del consenso utente: Allow the app to access TodoApp on your behalf.
    • State: Enabled
  9. Selezionare Aggiungi ambito per completare l'aggiunta dell'ambito.

  10. Si noti il valore dell'ambito, simile a api://<client-id>/access_as_user (detto ambito API Web ). È necessario l'ambito durante la configurazione del client.

  11. Selezionare Panoramica.

  12. Si noti l'ID applicazione (client) nella sezione Essentials (id applicazione API Web ). Questo valore è necessario per configurare il servizio back-end.

Aprire Visual Studio e selezionare il progetto TodoAppService.NET6.

  1. Fare clic con il pulsante destro del mouse sul progetto TodoAppService.NET6, quindi selezionare Gestisci pacchetti NuGet....

  2. Nella nuova scheda selezionare Sfoglia, quindi immettere Microsoft.Identity.Web nella casella di ricerca.

    Screenshot dell'aggiunta di M S A L NuGet in Visual Studio.

  3. Selezionare il pacchetto di Microsoft.Identity.Web, quindi premere Installa.

  4. Seguire le istruzioni per completare l'installazione del pacchetto.

  5. Aprire Program.cs. Aggiungere quanto segue all'elenco di istruzioni using:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
  1. Aggiungere il codice seguente direttamente sopra la chiamata a builder.Services.AddDbContext():
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
  .AddMicrosoftIdentityWebApi(builder.Configuration);
builder.Services.AddAuthorization();
  1. Aggiungere il codice seguente direttamente sopra la chiamata a app.MapControllers():
app.UseAuthentication();
app.UseAuthorization();

Il Program.cs dovrebbe essere simile al seguente:

using Microsoft.AspNetCore.Datasync;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
using TodoAppService.NET6.Db;
  
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
  
if (connectionString == null)
{
  throw new ApplicationException("DefaultConnection is not set");
}
  
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
  .AddMicrosoftIdentityWebApi(builder.Configuration);
builder.Services.AddAuthorization();
builder.Services.AddDbContext<AppDbContext>(options => options.UseSqlServer(connectionString));
builder.Services.AddDatasyncControllers();
  
var app = builder.Build();
  
// Initialize the database
using (var scope = app.Services.CreateScope())
{
  var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
  await context.InitializeDatabaseAsync().ConfigureAwait(false);
}
  
// Configure and run the web service.
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
  1. Modificare il Controllers\TodoItemController.cs. Aggiungere un attributo [Authorize] alla classe . La classe dovrebbe essere simile alla seguente:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Datasync;
using Microsoft.AspNetCore.Datasync.EFCore;
using Microsoft.AspNetCore.Mvc;
using TodoAppService.NET6.Db;

namespace TodoAppService.NET6.Controllers
{
  [Authorize]
  [Route("tables/todoitem")]
  public class TodoItemController : TableController<TodoItem>
  {
    public TodoItemController(AppDbContext context)
      : base(new EntityTableRepository<TodoItem>(context))
    {
    }
  }
}
  1. Modificare il appsettings.json. Aggiungere il blocco seguente:
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com",
    "ClientId": "<client-id>",
    "TenantId": "common"
  },

Sostituire il <client-id> con l'ID applicazione API Web registrato in precedenza. Al termine, dovrebbe essere simile al seguente:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com",
    "ClientId": "<client-id>",
    "TenantId": "common"
  },
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=TodoApp;Trusted_Connection=True"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

Pubblicare di nuovo il servizio in Azure:

  1. Fare clic con il pulsante destro del mouse sul progetto di TodoAppService.NET6, quindi selezionare Pubblica....
  2. Selezionare il pulsante Pubblica nell'angolo superiore destro della scheda.

Aprire un browser per https://yoursite.azurewebsites.net/tables/todoitem?ZUMO-API-VERSION=3.0.0. Si noti che il servizio restituisce ora una risposta 401, che indica che è necessaria l'autenticazione.

Screenshot del browser che mostra un errore.

Registrare l'app con il servizio di gestione delle identità

Microsoft Data Sync Framework include il supporto predefinito per qualsiasi provider di autenticazione che usa un token Json Web (JWT) all'interno di un'intestazione della transazione HTTP. Questa applicazione usa il Microsoft Authentication Library (MSAL) per richiedere tale token e autorizzare l'utente connesso al servizio back-end.

Configurare un'applicazione client nativa

È possibile registrare client nativi per consentire l'autenticazione alle API Web ospitate nell'app usando una libreria client, ad esempio Microsoft Identity Library (MSAL).

  1. Nel portale di Azure selezionare ID Microsoft Entra>Registrazioni app>Nuova registrazione.

  2. Nella pagina Registrare un'applicazione:

    • immettere un Nome per la registrazione dell'app. È possibile usare il nome native-quickstart per distinguerne uno da quello usato dal servizio back-end.
    • Selezionare Account in qualsiasi directory organizzativa (qualsiasi directory Microsoft Entra - Multi-tenant) e account Microsoft personali (ad esempio Skype, Xbox).
    • In URI di reindirizzamento:
      • Selezionare client pubblico (desktop & per dispositivi mobili)
      • Immettere l'URL quickstart://auth
  3. Selezionare Registra.

  4. Selezionare autorizzazioni API >Aggiungere un'autorizzazione>API personali.

  5. Selezionare la registrazione dell'app creata in precedenza per il servizio back-end. Se la registrazione dell'app non viene visualizzata, assicurarsi di aver aggiunto l'ambito access_as_user.

    Screenshot della registrazione dell'ambito nel portale di Azure.

  6. In Selezionare le autorizzazioniselezionare access_as_usere quindi selezionare Aggiungi autorizzazioni.

  7. Selezionare Autenticazione>applicazioni per dispositivi mobili e desktop.

  8. Selezionare la casella accanto a https://login.microsoftonline.com/common/oauth2/nativeclient.

  9. Selezionare la casella accanto a msal{client-id}://auth (sostituendo {client-id} con l'ID applicazione).

  10. Selezionare Aggiungi URI, quindi aggiungere http://localhost nel campo per URI aggiuntivi.

  11. Selezionare Salva nella parte inferiore della pagina.

  12. Selezionare Panoramica. Prendere nota del ID applicazione (client) (detto ID applicazione client native client) perché è necessario configurare l'app per dispositivi mobili.

Sono stati definiti tre URL di reindirizzamento:

  • http://localhost viene usato dalle applicazioni WPF.
  • https://login.microsoftonline.com/common/oauth2/nativeclient viene usato dalle applicazioni UWP.
  • msal{client-id}://auth viene usato dalle applicazioni per dispositivi mobili (Android e iOS).

Aggiungere Microsoft Identity Client all'app

Aprire la soluzione TodoApp.sln in Visual Studio e impostare il progetto TodoApp.Forms come progetto di avvio.

Aggiungere il Microsoft Identity Library (MSAL) al progetto della piattaforma:

  1. Fare clic con il pulsante destro del mouse sul progetto, quindi selezionare Gestisci pacchetti NuGet....

  2. Selezionare la scheda sfoglia .

  3. Immettere Microsoft.Identity.Client nella casella di ricerca, quindi premere INVIO.

  4. Selezionare il risultato Microsoft.Identity.Client, quindi fare clic su Installa.

    Screenshot della selezione di MSAL NuGet in Visual Studio.

  5. Accettare il contratto di licenza per continuare l'installazione.

Aggiungere l'ID client nativo e l'ambito back-end alla configurazione.

Aprire il progetto TodoApp.Data e modificare il file di Constants.cs. Aggiungere costanti per ApplicationId e Scopes:

  public static class Constants
  {
      /// <summary>
      /// The base URI for the Datasync service.
      /// </summary>
      public static string ServiceUri = "https://demo-datasync-quickstart.azurewebsites.net";

      /// <summary>
      /// The application (client) ID for the native app within Microsoft Entra ID
      /// </summary>
      public static string ApplicationId = "<client-id>";

      /// <summary>
      /// The list of scopes to request
      /// </summary>
      public static string[] Scopes = new[]
      {
          "<scope>"
      };
  }

Sostituire il <client-id> con l'ID applicazione native ricevuta durante la registrazione dell'applicazione client in Microsoft Entra ID e l'<scope> con l'ambito api Web copiato quando è stato usato Esporre un API durante la registrazione dell'applicazione di servizio.

Aprire il progetto TodoApp.Forms. Aggiungere un nuovo file denominato IPlatform.cs con il contenuto seguente:

using Microsoft.Identity.Client;

namespace TodoApp.Forms
{
    public interface IPlatform
    {
        IPublicClientApplication GetIdentityClient(string applicationId);
    }
}

Questa interfaccia viene usata più avanti per consentire al progetto condiviso di chiedere al progetto della piattaforma un client di identità adatto per la piattaforma.

Aprire App.xaml.cs. Aggiungere le istruzioni using seguenti:

using Microsoft.Datasync.Client;
using Microsoft.Identity.Client;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;

Nella classe App aggiungere due nuove proprietà:

public IPublicClientApplication IdentityClient { get; set; }
public IPlatform PlatformService { get; }

Modificare il costruttore per leggere:

public App(IPlatform platformService)
{
    InitializeComponent();

    PlatformService = platformService;
    TodoService = new RemoteTodoService(GetAuthenticationToken);
    MainPage = new NavigationPage(new MainPage(this, TodoService));
}

Aggiungere il metodo GetAuthenticationToken alla classe :

public async Task<AuthenticationToken> GetAuthenticationToken()
{
    if (IdentityClient == null)
    {
        IdentityClient = PlatformService.GetIdentityClient(Constants.ApplicationId);
    }

    var accounts = await IdentityClient.GetAccountsAsync();
    AuthenticationResult result = null;
    bool tryInteractiveLogin = false;

    try
    {
        result = await IdentityClient
            .AcquireTokenSilent(Constants.Scopes, accounts.FirstOrDefault())
            .ExecuteAsync();
    }
    catch (MsalUiRequiredException)
    {
        tryInteractiveLogin = true;
    }
    catch (Exception ex)
    {
        Debug.WriteLine($"MSAL Silent Error: {ex.Message}");
    }

    if (tryInteractiveLogin)
    {
        try
        {
            result = await IdentityClient
                .AcquireTokenInteractive(Constants.Scopes)
                .ExecuteAsync()
                .ConfigureAwait(false);
        }
        catch (Exception ex)
        {
            Debug.WriteLine($"MSAL Interactive Error: {ex.Message}");
        }
    }

    return new AuthenticationToken
    {
        DisplayName = result?.Account?.Username ?? "",
        ExpiresOn = result?.ExpiresOn ?? DateTimeOffset.MinValue,
        Token = result?.AccessToken ?? "",
        UserId = result?.Account?.Username ?? ""
    };
}

Il metodo GetAuthenticationToken() funziona con Microsoft Identity Library (MSAL) per ottenere un token di accesso adatto per autorizzare l'utente connesso al servizio back-end. Questa funzione viene quindi passata al RemoteTodoService per la creazione del client. Se l'autenticazione ha esito positivo, il AuthenticationToken viene generato con i dati necessari per autorizzare ogni richiesta. In caso contrario, viene generato un token non valido scaduto.

Configurare l'app Android per l'autenticazione

Aprire il progetto TodoApp.Forms.Android. Creare una nuova classe MsalActivity con il codice seguente:

using Android.App;
using Android.Content;
using Microsoft.Identity.Client;

namespace TodoApp.Forms.Droid
{
    [Activity(Exported = true)]
    [IntentFilter(new[] { Intent.ActionView },
        Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault },
        DataHost = "auth",
        DataScheme = "msal{client-id}")]
    public class MsalActivity : BrowserTabActivity
    {
    }
}

Sostituire {client-id} con l'ID applicazione del client nativo (uguale a Constants.ApplicationId).

Se il progetto è destinato a Android versione 11 (API versione 30) o successiva, è necessario aggiornare il AndroidManifest.xml per soddisfare i requisiti di visibilità dei pacchetti Android . Aprire TodoApp.Forms.Android/Properties/AndroidManifest.xml e aggiungere i nodi di queries/intent seguenti al nodo manifest:

<manifest>
  ...
  <queries>
    <intent>
      <action android:name="android.support.customtabs.action.CustomTabsService" />
    </intent>
  </queries>
</manifest>

Aprire MainActivity.cs. Aggiungere IPlatform alla definizione della classe MainActivity:

public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, IPlatform

Modificare la chiamata LoadApplication() nel metodo OnCreate():

protected override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);

    Xamarin.Essentials.Platform.Init(this, savedInstanceState);
    global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
    LoadApplication(new App(this));
}

Aggiungere il codice seguente alla fine della classe :

protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
{
    base.OnActivityResult(requestCode, resultCode, data);
    // Return control to MSAL
    AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(requestCode, resultCode, data);
}

public IPublicClientApplication GetIdentityClient(string applicationId)
{
    var identityClient = PublicClientApplicationBuilder.Create(applicationId)
        .WithAuthority(AzureCloudInstance.AzurePublic, "common")
        .WithRedirectUri($"msal{applicationId}://auth")
        .WithParentActivityOrWindow(() => this)
        .Build();
    return identityClient;
}

Quando il progetto condiviso richiede l'autenticazione, ottiene un client di identità da GetIdentityClient(), quindi passa a un'attività interna che apre il browser di sistema. Al termine dell'autenticazione, il browser di sistema reindirizza all'URL di reindirizzamento definito (msal{client-id}://auth). Il MsalActivity intercettare l'URL di reindirizzamento, che quindi torna all'attività principale chiamando OnActivityResult(). Viene quindi chiamato l'helper di autenticazione MSAL, che completa la transazione.

Configurare l'app iOS per l'autenticazione

Aprire il file AppDelegate.cs nel progetto TodoApp.Forms.iOS. Aggiungere IPlatform alla definizione della classe AppDelegate:

public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate, IPlatform

Modificare il metodo FinishedLaunching() per leggere:

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    global::Xamarin.Forms.Forms.Init();
    LoadApplication(new App(this));
    return base.FinishedLaunching(app, options);
}

Aggiungere il codice seguente alla fine della classe :

public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
    bool result = AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(url);
    return result || base.OpenUrl(app, url, options);
}

public IPublicClientApplication GetIdentityClient(string applicationId)
{
    var identityClient = PublicClientApplicationBuilder.Create(applicationId)
        .WithIosKeychainSecurityGroup("com.microsoft.adalcache")
        .WithRedirectUri($"msal{applicationId}://auth")
        .Build();
    return identityClient;
}

Aggiungere l'accesso keychain al Entitlements.plist:

  1. Aprire il file Entitlements.plist.

  2. Selezionare Keychain.

  3. Selezionare Aggiungi nuovo nei gruppi keychain.

  4. Immettere com.microsoft.adalcache come valore:

    Screenshot che mostra i diritti di i O S.

Aggiungere i diritti personalizzati al progetto:

  1. Fare clic con il pulsante destro del mouse sul progetto di TodoApp.Forms.iOS, quindi selezionare Proprietà.

  2. Selezionare firma del bundle iOS.

  3. Selezionare il pulsante ... accanto al campo diritti personalizzati.

  4. Selezionare Entitlements, quindi selezionare Apri.

  5. Premere CTRL+S per salvare il progetto.

    Screenshot che mostra le proprietà di firma del bundle i O S.

Testare l'app Android

Impostare TodoApp.Forms.Android come progetto di avvio, quindi premere F5 per compilare ed eseguire l'app. All'avvio dell'app viene richiesto di accedere all'app. Alla prima esecuzione viene chiesto di fornire il consenso all'app. Al termine dell'autenticazione, l'app viene eseguita normalmente.

Testare l'app iOS

Nota

Poiché l'app iOS richiede l'accesso keychain, è necessario configurare un profilo di provisioning. Un profilo di provisioning richiede un dispositivo reale o un account Apple Developer a pagamento (se si usa il simulatore). Per altre informazioni, vedere Provisioning dei dispositivi per iOS.

Impostare TodoApp.Forms.iOS come progetto di avvio, quindi premere F5 per compilare ed eseguire l'app. All'avvio dell'app viene richiesto di accedere all'app. Alla prima esecuzione viene chiesto di fornire il consenso all'app. Al termine dell'autenticazione, l'app viene eseguita normalmente.

Passaggi successivi

Configurare quindi l'applicazione in modo che funzioni offline l'implementazione di un archivio offline.

Altre informazioni