Добавление проверки подлинности в приложение MAUI .NET

В этом руководстве описано, как добавить проверку подлинности Майкрософт в проект TodoApp с помощью идентификатора Microsoft Entra. Прежде чем завершить работу с этим руководством, убедитесь, что вы создали проект и развернули серверную часть.

Совет

Хотя мы используем идентификатор Microsoft Entra для проверки подлинности, вы можете использовать любую библиотеку проверки подлинности, которую вы хотите использовать с мобильными приложениями Azure.

Добавление проверки подлинности в серверную службу

Серверная служба — это стандартная служба ASP.NET 6. В любом руководстве показано, как включить проверку подлинности для службы ASP.NET 6, которая работает с мобильными приложениями Azure.

Чтобы включить проверку подлинности Microsoft Entra для серверной службы, необходимо:

  • Регистрация приложения с Microsoft Entra ID.
  • Добавьте проверку подлинности проверка в проект серверной части ASP.NET 6.

Регистрация приложения

Сначала зарегистрируйте веб-API в клиенте Microsoft Entra и добавьте область, выполнив следующие действия:

  1. Войдите на портал Azure.

  2. Если у вас есть доступ к нескольким клиентам, используйте фильтр каталогов и подписок в верхнем меню, чтобы переключиться на клиент, в котором требуется зарегистрировать приложение.

  3. Найдите и выберите Microsoft Entra ID.

  4. В разделе Управление выберите Регистрация приложений>Создать регистрацию.

    • Имя: введите имя приложения, например Краткое руководство по TodoApp. Пользователи приложения увидят это имя. Его можно будет изменить впоследствии.
    • Поддерживаемые типы учетных записей: учетные записи в любом каталоге организации (любой каталог Microsoft Entra — Multitenant) и личные учетные записи Майкрософт (например, Skype, Xbox)
  5. Выберите Зарегистрировать.

  6. В разделе Управление выберите Предоставление API>Добавить группу.

  7. Для URI идентификатора приложения примите значение по умолчанию, нажав кнопку "Сохранить" и продолжить.

  8. Введите следующие сведения:

    • Имя области: access_as_user
    • Кто может предоставить согласие?: Администратор и пользователи
    • Отображаемое имя согласия администратора: Access TodoApp
    • Описание согласия администратора: Allows the app to access TodoApp as the signed-in user.
    • Отображаемое имя согласия пользователя: Access TodoApp
    • Описание согласия пользователя: Allow the app to access TodoApp on your behalf.
    • Состояние: включено
  9. Выберите Добавить область, чтобы завершить добавление области.

  10. Обратите внимание на значение область, аналогичное api://<client-id>/access_as_user (называемой областью веб-API). Вам потребуется область при настройке клиента.

  11. Выберите Обзор.

  12. Обратите внимание на идентификатор приложения (клиента) в разделе Essentials (идентификатор приложения веб-API). Это значение необходимо для настройки серверной службы.

Откройте Visual Studio и выберите TodoAppService.NET6 проект.

  1. Щелкните проект правой TodoAppService.NET6 кнопкой мыши и выберите пункт "Управление пакетами NuGet...".

  2. На новой вкладке нажмите кнопку "Обзор", а затем в поле поиска введите Microsoft.Identity.Web .

    Screenshot of adding the M S A L NuGet in Visual Studio.

  3. Microsoft.Identity.Web Выберите пакет, а затем нажмите кнопку "Установить".

  4. Следуйте инструкциям, чтобы завершить установку пакета.

  5. Открыть Program.cs. Добавьте следующее в список операторов using :

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
  1. Добавьте следующий код непосредственно над вызовом builder.Services.AddDbContext():
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
  .AddMicrosoftIdentityWebApi(builder.Configuration);
builder.Services.AddAuthorization();
  1. Добавьте следующий код непосредственно над вызовом app.MapControllers():
app.UseAuthentication();
app.UseAuthorization();

Ваш Program.cs теперь должен выглядеть так:

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. Измените Controllers\TodoItemController.csобъект . [Authorize] Добавьте атрибут в класс. Класс должен выглядеть следующим образом:
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. Измените appsettings.jsonобъект . Добавьте следующий блок:
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com",
    "ClientId": "<client-id>",
    "TenantId": "common"
  },

Замените <client-id>идентификатор приложения веб-API, записанный ранее. После завершения он должен выглядеть следующим образом:

{
  "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": "*"
}

Опубликуйте службу в Azure еще раз:

  1. Щелкните проект правой TodoAppService.NET6 кнопкой мыши и выберите "Опубликовать...".
  2. Нажмите кнопку "Опубликовать" в правом верхнем углу вкладки.

Откройте в браузере страницу https://yoursite.azurewebsites.net/tables/todoitem?ZUMO-API-VERSION=3.0.0. Обратите внимание, что служба теперь возвращает ответ, указывающий 401 , что требуется проверка подлинности.

Screenshot of the browser showing an error.

Регистрация приложения в службе удостоверений

Платформа синхронизации данных Майкрософт имеет встроенную поддержку для любого поставщика проверки подлинности, использующего веб-токен Json (JWT) в заголовке транзакции HTTP. Это приложение использует библиотеку проверки подлинности Майкрософт (MSAL) для запроса такого маркера и авторизации пользователя, выполнившего вход в серверную службу.

Настройка собственного клиентского приложения

Вы можете зарегистрировать собственные клиенты, чтобы разрешить проверку подлинности размещенных в приложении веб-API с помощью клиентской библиотеки, такой как Библиотека идентификации Майкрософт (MSAL).

  1. В портал Azure выберите идентификатор Microsoft Entra ID> Регистрация приложений> New.

  2. На странице регистрации приложения:

    • введите имя для регистрации приложения. Вы можете использовать имя native-quickstart , чтобы отличить его от того, который используется серверной службой.
    • Выберите учетные записи в любом каталоге организации (любой каталог Microsoft Entra — Multitenant) и личных учетных записей Майкрософт (например, Skype, Xbox).
    • В URI перенаправления:
      • Выбор общедоступного клиента (мобильный и настольный компьютер)
      • Введите URL-адрес quickstart://auth
  3. Выберите Зарегистрировать.

  4. Выберите Разрешения API>Добавить разрешение>Мои API.

  5. Выберите регистрацию приложения, созданную ранее для серверной службы. Если вы не видите регистрацию приложения, убедитесь, что вы добавили access_as_user область.

    Screenshot of the scope registration in the Azure portal.

  6. В разделе "Выбор разрешений" выберите access_as_user и нажмите кнопку "Добавить разрешения".

  7. Выберите мобильные и классические приложения проверки подлинности>.

  8. Установите флажок рядом с https://login.microsoftonline.com/common/oauth2/nativeclient.

  9. Установите флажок рядом msal{client-id}://auth с полем (замена {client-id} идентификатором приложения).

  10. Выберите "Добавить URI", а затем добавьте http://localhost в поле дополнительные URI.

  11. В нижней части страницы нажмите кнопку Сохранить.

  12. Выберите Обзор. Запишите идентификатор приложения (клиента), который называется идентификаторомсобственного клиентского приложения, так как он необходим для настройки мобильного приложения.

Мы определили три URL-адреса перенаправления:

  • http://localhost используется приложениями WPF.
  • https://login.microsoftonline.com/common/oauth2/nativeclient используется приложениями UWP.
  • msal{client-id}://auth используется мобильными приложениями (Android и iOS).

Добавление клиента удостоверений Майкрософт в приложение

TodoApp.sln Откройте решение в Visual Studio и задайте TodoApp.MAUI проект в качестве запускаемого проекта. Добавьте в проект библиотеку удостоверений Майкрософт (MSALTodoApp.MAUI):

Добавьте библиотеку удостоверений Майкрософт (MSAL) в проект платформы:

  1. Щелкните проект правой кнопкой мыши и выберите Управление пакетами NuGet….

  2. Откройте вкладку Browse (Обзор).

  3. В окне поиска введите Microsoft.Identity.Client и нажмите клавишу ВВОД.

  4. Выберите результат Microsoft.Identity.Client, а затем щелкните Установить.

    Screenshot of selecting the MSAL NuGet in Visual Studio.

  5. Примите условия лицензионного соглашения, чтобы продолжить установку.

Добавьте собственный идентификатор клиента и серверную область в конфигурацию.

Откройте проект и измените TodoApp.DataConstants.cs файл. Добавление констант для ApplicationId и 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>"
      };
  }

<client-id>Замените идентификатор собственного клиентского приложения, полученный при регистрации клиентского приложения в идентификаторе Microsoft Entra ID, и <scope>область веб-API, скопированную при использовании API при регистрации приложения-службы.

Откройте класс MainPage.xaml.cs в проекте TodoApp.MAUI. Добавьте следующие операторы using :

using Microsoft.Datasync.Client;
using Microsoft.Identity.Client;
using System.Diagnostics;

MainPage В классе добавьте новое свойство:

public IPublicClientApplication IdentityClient { get; set; }

Настройте конструктор для чтения:

public MainPage()
{
    InitializeComponent();
    TodoService = new RemoteTodoService(GetAuthenticationToken);
    viewModel = new MainViewModel(this, TodoService);
    BindingContext = viewModel;
}

Добавьте метод GetAuthenticationToken в класс:

public async Task<AuthenticationToken> GetAuthenticationToken()
{
    if (IdentityClient == null)
    {
#if ANDROID
        IdentityClient = PublicClientApplicationBuilder
            .Create(Constants.ApplicationId)
            .WithAuthority(AzureCloudInstance.AzurePublic, "common")
            .WithRedirectUri($"msal{Constants.ApplicationId}://auth")
            .WithParentActivityOrWindow(() => Platform.CurrentActivity)
            .Build();
#elif IOS
        IdentityClient = PublicClientApplicationBuilder
            .Create(Constants.ApplicationId)
            .WithAuthority(AzureCloudInstance.AzurePublic, "common")
            .WithIosKeychainSecurityGroup("com.microsoft.adalcache")
            .WithRedirectUri($"msal{Constants.ApplicationId}://auth")
            .Build();
#else
        IdentityClient = PublicClientApplicationBuilder
            .Create(Constants.ApplicationId)
            .WithAuthority(AzureCloudInstance.AzurePublic, "common")
            .WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient")
            .Build();
#endif
    }

    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();
        }
        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 ?? ""
    };
}

Метод GetAuthenticationToken() работает с библиотекой удостоверений Майкрософт (MSAL), чтобы получить маркер доступа, подходящий для авторизации вошедшего пользователя в серверную службу. Затем эта функция передается RemoteTodoService в клиент для создания клиента. Если проверка подлинности выполнена успешно, создается данные, AuthenticationToken необходимые для авторизации каждого запроса. Если нет, вместо этого создается неправильный маркер с истекшим сроком действия.

Мы можем добавить любые параметры для конкретной платформы с помощью #if областей с описателями платформы. Например, Android требует указать родительское действие, которое передается на вызывающую страницу.

Настройка приложения Android для проверки подлинности

Создайте класс Platforms\Android\MsalActivity.cs со следующим кодом:

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

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

Замените {client-id} идентификатором приложения собственного клиента (то же самое, что Constants.ApplicationIdи ).

Если проект предназначен для Android версии 11 (API версии 30) или более поздней версии, необходимо обновить приложение AndroidManifest.xml для соответствия требованиям к видимости пакета Android. Откройте Platforms/Android/AndroidManifest.xml и добавьте следующие queries/intent узлы в manifest узел:

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

Открыть MauiProgram.cs. Добавьте следующие using инструкции в начало файла:

using Microsoft.Identity.Client;

Обновите построитель до следующего кода:

    builder
        .UseMauiApp<App>()
        .ConfigureLifecycleEvents(events =>
        {
#if ANDROID
            events.AddAndroid(platform =>
            {
                platform.OnActivityResult((activity, rc, result, data) =>
                {
                    AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(rc, result, data);
                });
            });
#endif
        })
        .ConfigureFonts(fonts =>
        {
            fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
            fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
        });

Если вы выполняете этот шаг после обновления приложения для iOS, добавьте код, указанный #if ANDROID (включая #if и #endif). Компилятор выбирает правильный фрагмент кода на основе скомпилированной платформы. Этот код можно поместить либо до, либо после существующего блока для iOS.

Когда Android требует проверки подлинности, он получает клиент удостоверений, а затем переключается на внутреннее действие, которое открывает системный браузер. После завершения проверки подлинности системный браузер перенаправляется на определенный URL-адрес перенаправления (msal{client-id}://auth). Перехватывает MsalActivity URL-адрес перенаправления, который затем переключается обратно на основное действие путем вызова OnActivityResult(). Метод OnActivityResult() вызывает вспомогательное средство проверки подлинности MSAL для завершения транзакции.

Тестирование приложения Android

Задайте TodoApp.MAUI в качестве запускаемого проекта, выберите эмулятор Android в качестве целевого объекта, а затем нажмите клавишу F5 , чтобы создать и запустить приложение. При запуске приложения вам будет предложено войти в приложение. При первом запуске вам будет предложено предоставить согласие на приложение. После завершения проверки подлинности приложение запускается как обычное.

Тестирование приложения Windows

Задайте TodoApp.MAUI в качестве запускаемого проекта, выберите компьютер Windows в качестве целевого объекта, а затем нажмите клавишу F5 , чтобы создать и запустить приложение. При запуске приложения вам будет предложено войти в приложение. При первом запуске вам будет предложено предоставить согласие на приложение. После завершения проверки подлинности приложение запускается как обычное.

Следующие шаги

Затем настройте приложение для работы в автономном режиме, реализуя автономное хранилище.

Дополнительные материалы