將驗證新增至 Xamarin.Forms 應用程式
注意
此產品已淘汰。 如需使用 .NET 8 或更新版本的專案取代專案,請參閱 Community Toolkit Datasync 連結庫。
在本教學課程中,您會使用 Microsoft Entra 識別碼,將Microsoft驗證新增至您的應用程式。 完成本教學課程之前,請確定您已 建立專案,並部署後端。
注意
由於 iOS 應用程式需要金鑰鏈存取,因此您必須設定 iOS 佈建設定檔。 布建配置檔需要實際的 iOS 裝置或付費的 Apple 開發人員帳戶(如果使用模擬器)。 如果您因為這項限制而無法使用驗證,您可以略過本教學課程,並繼續將 離機存取新增至應用程式。
提示
雖然我們使用 Microsoft Entra ID 進行驗證,但您可以使用任何您想要與 Azure Mobile Apps 搭配使用的驗證連結庫。
將驗證新增至後端服務
您的後端服務是標準 ASP.NET 6 服務。 任何示範如何啟用 ASP.NET 6 服務驗證與 Azure Mobile Apps 搭配運作的教學課程。
若要為後端服務啟用Microsoft Entra 驗證,您需要:
- 使用 Microsoft Entra 識別子註冊應用程式。
- 將驗證檢查新增至 ASP.NET 6 個後端專案。
註冊應用程式
首先,在您的 Microsoft Entra 租用戶中註冊 Web API,並遵循下列步驟來新增範圍:
登入 Azure 入口網站。
如果您有多個租使用者的存取權,請使用頂端功能表中的 [目錄 + 訂用帳戶] 篩選,切換至您要在其中註冊應用程式的租使用者。
搜尋並選擇 Microsoft Entra ID。
在 [[管理] 下,選取 [應用程式註冊],>[新增註冊]。
- 名稱:輸入應用程式的名稱;例如,TodoApp 快速入門。 您應用程式的使用者會看到此名稱。 您可以稍後加以變更。
- 支援的帳戶類型:任何組織目錄中的 帳戶(任何Microsoft Entra 目錄 - 多租使用者)和個人Microsoft帳戶(例如Skype、Xbox)
選取 [[註冊]。
在 [管理] 下,選取 [[公開 API>[新增範圍]。
針對 應用程式識別碼 URI,請選取 [儲存並繼續],以接受預設值。
輸入下列詳細資料:
-
範圍名稱:
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.
- 狀態:已啟用
-
範圍名稱:
選取 [[新增範圍],以完成新增範圍。
請注意範圍的值,類似於
api://<client-id>/access_as_user
(稱為 Web API 範圍)。 設定用戶端時,您需要範圍。選取 概觀。
請注意 Essentials 區段中的 應用程式 (用戶端) 識別碼 (稱為 Web API 應用程式識別碼)。 您需要此值來設定後端服務。
開啟 Visual Studio,然後選取 TodoAppService.NET6
專案。
以滑鼠右鍵按下
TodoAppService.NET6
項目,然後選取 [管理 NuGet 套件...。在新索引標籤中,選取 [流覽],然後在搜尋方塊中輸入 Microsoft.Identity.Web。
選擇
Microsoft.Identity.Web
套件,然後按 [安裝]。請遵循提示來完成套件的安裝。
開啟
Program.cs
。 將下列內容新增至using
語句清單:
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
- 將下列程式代碼直接新增至
builder.Services.AddDbContext()
呼叫上方:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration);
builder.Services.AddAuthorization();
- 將下列程式代碼直接新增至
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();
- 編輯
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))
{
}
}
}
- 編輯
appsettings.json
。 新增下列區塊:
"AzureAd": {
"Instance": "https://login.microsoftonline.com",
"ClientId": "<client-id>",
"TenantId": "common"
},
將 <client-id>
取代為您稍早記錄的 Web 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:
- 以滑鼠右鍵按下
TodoAppService.NET6
項目,然後選取 [[發佈...]。 - 選取索引標籤右上角的 [[發佈] 按鈕。
開啟瀏覽器以 https://yoursite.azurewebsites.net/tables/todoitem?ZUMO-API-VERSION=3.0.0
。 請注意,服務現在會傳回 401
回應,表示需要驗證。
向身分識別服務註冊您的應用程式
Microsoft數據同步架構內建支援任何在 HTTP 交易標頭內使用 Json Web 令牌 (JWT) 的驗證提供者。 此應用程式會使用 Microsoft 驗證連結庫 (MSAL) 來要求這類令牌,並將登入的使用者授權給後端服務。
設定原生用戶端應用程式
您可以使用用戶端連結庫,例如Microsoft身分識別連結庫(MSAL),註冊原生用戶端,以允許驗證裝載在應用程式中的Web API。
在 Azure 入口網站中,選取 [Microsoft [專案標識符]>[應用程式註冊]>[新增註冊]。
在 [註冊應用程式 頁面中:
- 輸入應用程式註冊 名稱。 您可能想要使用名稱
native-quickstart
來區別後端服務所使用的名稱。 - 選取任何組織目錄中的 帳戶(任何Microsoft Entra 目錄 - 多租使用者)和個人Microsoft帳戶(例如Skype、Xbox)。
- 在 重新導向 URI:
- 選取 [公用用戶端] [行動裝置 & 桌面]
- 輸入 URL
quickstart://auth
- 輸入應用程式註冊 名稱。 您可能想要使用名稱
選取 [[註冊]。
選取 [API 許可權],>[新增我的 API>的許可權]。
選取您稍早為後端服務建立的應用程式註冊。 如果您沒有看到應用程式註冊,請確定您已新增 access_as_user 範圍。
在 [選取許可權],選取 [access_as_user],然後選取 [[新增許可權]。
選取 [
驗證] [行動裝置和傳統型應用程式]。 核取
https://login.microsoftonline.com/common/oauth2/nativeclient
旁的方塊。核取
msal{client-id}://auth
旁的方塊(以您的應用程式識別碼取代{client-id}
)。選取 [[新增 URI],然後在字段中新增
http://localhost
以取得額外的 URI。選取頁面底部的 [儲存]。
選取 概觀。 記下 應用程式 (用戶端) 識別碼 (稱為 Native Client Application ID),因為您需要它才能設定行動應用程式。
我們已定義三個重新導向 URL:
- WPF 應用程式會使用
http://localhost
。 - UWP 應用程式會使用
https://login.microsoftonline.com/common/oauth2/nativeclient
。 - 行動裝置 (Android 和 iOS) 應用程式會使用
msal{client-id}://auth
。
將 Microsoft Identity Client 新增至您的應用程式
在 Visual Studio 中開啟 TodoApp.sln
方案,並將 TodoApp.Forms
項目設定為啟始專案。
將 Microsoft 識別連結庫 (MSAL) 新增至平台專案:
以滑鼠右鍵按下項目,然後選取 [管理 NuGet 套件...。
選取 [流覽] 索引標籤。
在搜尋方塊中輸入
Microsoft.Identity.Client
,然後按 Enter 鍵。選取
Microsoft.Identity.Client
結果,然後按兩下 [安裝]。接受許可協議以繼續安裝。
將原生用戶端標識碼和後端範圍新增至組態。
開啟 TodoApp.Data
項目並編輯 Constants.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 中註冊用戶端應用程式時收到的 Native Client Application ID,並將 <scope>
取代為您在註冊服務應用程式時 公開 API 時所複製的 Web API 範圍。
開啟 TodoApp.Forms
專案。 使用下列內容新增名為 IPlatform.cs
的新檔案:
using Microsoft.Identity.Client;
namespace TodoApp.Forms
{
public interface IPlatform
{
IPublicClientApplication GetIdentityClient(string applicationId);
}
}
稍後會使用此介面,讓共用專案向平臺專案詢問適合平臺的身分識別用戶端。
開啟 App.xaml.cs
。 新增下列 using
語句:
using Microsoft.Datasync.Client;
using Microsoft.Identity.Client;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
在 App
類別中,新增兩個新屬性:
public IPublicClientApplication IdentityClient { get; set; }
public IPlatform PlatformService { get; }
調整建構函式以讀取:
public App(IPlatform platformService)
{
InitializeComponent();
PlatformService = platformService;
TodoService = new RemoteTodoService(GetAuthenticationToken);
MainPage = new NavigationPage(new MainPage(this, TodoService));
}
將 GetAuthenticationToken
方法新增至 類別:
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 ?? ""
};
}
GetAuthenticationToken()
方法可與 Microsoft Identity Library (MSAL) 搭配運作,以取得適合將登入使用者授權給後端服務的存取令牌。 接著,此函式會傳遞至 RemoteTodoService
以建立用戶端。 如果驗證成功,就會產生 AuthenticationToken
,其中包含授權每個要求所需的數據。 如果沒有,則會改為產生過期的不正確令牌。
設定 Android 應用程式以進行驗證
開啟 TodoApp.Forms.Android
專案。 使用下列程式代碼建立新的類別 MsalActivity
:
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
{
}
}
以原生用戶端的應用程式識別碼取代 {client-id}
(這與 Constants.ApplicationId
相同)。
如果您的專案以 Android 11 版(API 第 30 版)或更新版本為目標,您必須更新您的 TodoApp.Forms.Android/Properties/AndroidManifest.xml
,並將下列 queries/intent
節點新增至 manifest
節點:
<manifest>
...
<queries>
<intent>
<action android:name="android.support.customtabs.action.CustomTabsService" />
</intent>
</queries>
</manifest>
開啟 MainActivity.cs
。 將 IPlatform
新增至 MainActivity
類別的定義:
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, IPlatform
在 OnCreate()
方法中變更 LoadApplication()
呼叫:
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));
}
將下列程式代碼新增至 類別底部:
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;
}
當共享專案需要驗證時,它會從 GetIdentityClient()
取得身分識別客戶端,然後切換至開啟系統瀏覽器的內部活動。 驗證完成後,系統瀏覽器會重新導向至定義的重新導向 URL (msal{client-id}://auth
)。
MsalActivity
會擷取重新導向 URL,然後藉由呼叫 OnActivityResult()
切換回主要活動。 然後,這會呼叫 MSAL 驗證協助程式,以完成交易。
設定 iOS 應用程式以進行驗證
在 TodoApp.Forms.iOS
項目中開啟 AppDelegate.cs
檔案。 將 IPlatform
新增至 AppDelegate
類別的定義:
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate, IPlatform
變更 FinishedLaunching()
方法以讀取:
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App(this));
return base.FinishedLaunching(app, options);
}
將下列程式代碼新增至 類別的結尾:
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;
}
將金鑰鏈存取新增至 Entitlements.plist
:
開啟
Entitlements.plist
檔案。選取 Keychain。
選取 [在密鑰鏈群組中新增。
輸入
com.microsoft.adalcache
作為值:
將自訂權利新增至專案:
以滑鼠右鍵按下
TodoApp.Forms.iOS
項目,然後選取 [[屬性]。選擇 [iOS 套件組合簽署。
選取 [自定義權利] 字段旁的 [...] 按鈕。
選取 [
Entitlements
],然後選取 [[開啟]。按 Ctrl+S 儲存專案。
測試 Android 應用程式
將 TodoApp.Forms.Android
設定為啟始專案,然後按 F5 建置並執行應用程式。 當應用程式啟動時,系統會提示您登入應用程式。 在第一次執行時,系統會要求您同意應用程式。 驗證完成後,應用程式會正常執行。
測試 iOS 應用程式
注意
由於 iOS 應用程式需要金鑰鏈存取權,因此您必須設定佈建配置檔。 布建配置檔需要實際裝置或付費的Apple開發人員帳戶(如果使用模擬器)。 如需詳細資訊,請參閱 iOS的裝置布建。
將 TodoApp.Forms.iOS
設定為啟始專案,然後按 F5 建置並執行應用程式。 當應用程式啟動時,系統會提示您登入應用程式。 在第一次執行時,系統會要求您同意應用程式。 驗證完成後,應用程式會正常執行。
後續步驟
接下來,實作離線存放區,設定您的應用程式以離線運作。
進一步閱讀
- 快速入門:使用Microsoft身分識別平台保護Web API
- 使用 MSAL.NET
Xamarin Android 的設定需求和疑難解答秘訣 - 使用 Xamarin iOS 搭配 MSAL.NET的考虑
- 案例:呼叫 Web API 的行動應用程式