احراز هویت با MSAL و Microsoft Entra ID در .NET MAUI: راهنمای عملی iOS، اندروید و ویندوز در ۲۰۲۶
همه چیز دربارهی یکپارچهسازی MSAL.NET با Microsoft Entra ID در .NET MAUI ۲۰۲۶: از ثبت اپلیکیشن و Redirect URI گرفته تا Broker، سریالسازی امن Token Cache، پشتیبانی WAM در ویندوز و External ID برای کاربران خارجی.
احراز هویت با MSAL و Microsoft Entra ID در .NET MAUI یعنی استفاده از کتابخانهی Microsoft.Identity.Client برای گرفتن توکن دسترسی از Entra ID (نام جدید Azure AD) با جریان Authorization Code + PKCE، ذخیرهسازی امن توکن در کش پلتفرم و تمدید سکوت (Silent Refresh) در دفعات بعدی. در MAUI 9 و بالاتر، MSAL از سه پلتفرم iOS، اندروید و ویندوز بهصورت یکپارچه پشتیبانی میکند و برای رولاوتهای سازمانی، فعالسازی Broker (Authenticator یا WAM) عملاً اجباری است.
MSAL.NET نسخه ۴.۶۶ در ۲۰۲۶ پشتیبانی رسمی از net8.0-ios، net8.0-android، net8.0-windows و net10.0 در MAUI را دارد و جایگزین کاملی برای ADAL منقضیشده است.
برای رفع مشکل بازگشت از مرورگر در اندروید و iOS، باید Redirect URI با اسکیم msauth و MsalActivity/OpenUrl در پروژه ثبت شود.
فعالسازی Broker از طریق Microsoft Authenticator در موبایل و WAM در ویندوز، هم Conditional Access را قابل اجرا میکند و هم SSO با سایر اپهای سازمانی را فراهم میسازد.
سریالسازی Token Cache با Microsoft.Identity.Client.Extensions.Msal در ترکیب با SecureStorage باعث میشود کاربر پس از راهاندازی مجدد اپ نیاز به لاگین دوباره نداشته باشد.
Microsoft Entra External ID (جانشین Azure AD B2C) با همان API و صرفاً تغییر Authority کار میکند و برای اپهای مصرفکننده مناسب است.
در ۹۹٪ موارد ابتدا AcquireTokenSilent فراخوانی میشود و در صورت MsalUiRequiredException به AcquireTokenInteractive برمیگردیم.
MSAL چیست و چرا برای MAUI ضروری است؟
Microsoft Authentication Library (MSAL) کتابخانهی رسمی مایکروسافت برای گرفتن توکن OAuth 2.0 و OpenID Connect از Microsoft Entra ID، حسابهای شخصی مایکروسافت و مستأجران External ID است. برخلاف ADAL که در ژوئن ۲۰۲۳ به پایان پشتیبانی رسید، MSAL از جریان امن Authorization Code + PKCE استفاده میکند و برخلاف پیادهسازیهای دستی OAuth، منطق پیچیدهی مدیریت refresh token، کش، امضای PoP و Continuous Access Evaluation را داخل خود کپسوله میکند. صادقانه بگویم، بار اولی که سعی کردم OAuth را «دستی» در یک اپ Xamarin.Forms پیاده کنم، سه هفته وقتم را روی edge caseهای refresh token هدر دادم. بعد از آن دیگر هیچوقت به این ایده برنگشتم.
در .NET MAUI 9 و بالاتر، بستهی Microsoft.Identity.Client با هر سه پلتفرم iOS، اندروید و WinUI سازگار است و از پروژهی TFM چندگانهی MAUI بهصورت شفاف پشتیبانی میکند. اهمیت واقعی MSAL در اپهای سازمانی (که در تجربهی من رولاوتهای MAUI برای صنایع تحت رگولاتوری اغلب همین دستهاند) از سه چیز میآید: پشتیبانی Broker برای اجرای سیاستهای Conditional Access، مدیریت خودکار انقضای توکن، و SSO یکپارچه با Outlook، Teams و سایر اپهای مایکروسافت روی همان دستگاه. اگر میخواهید یک نمای کلی از سایر روشهای احراز هویت داشته باشید، مقالهی احراز هویت JWT در .NET MAUI رویکرد سبکتری را برای بکاندهای سفارشی پوشش میدهد.
آمادهسازی: ثبت اپلیکیشن در Microsoft Entra ID
پیش از نوشتن حتی یک خط کد، باید اپلیکیشن را در پرتال Entra ID ثبت کنید تا Client ID، Tenant ID و Redirect URIهای مجاز را دریافت کنید. به پرتال Microsoft Entra بروید، از منوی چپ App registrations را باز کنید و روی New registration کلیک کنید. یک نام برای اپلیکیشن انتخاب کنید و در بخش Supported account types بسته به نیاز خود، «تنها این مستأجر»، «چند مستأجره» یا «حسابهای شخصی + کاری» را برگزینید.
در قسمت Redirect URI، پلتفرم Public client/native (mobile & desktop) را انتخاب کنید. سه URI زیر را اضافه کنید:
msal{CLIENT_ID}://auth برای iOS و اندروید.
http://localhost برای WinUI بدون Broker.
ms-appx-web://microsoft.aad.brokerplugin/{CLIENT_ID} برای WinUI با WAM.
پس از ایجاد اپ، به تب Authentication بروید و مطمئن شوید که گزینهی Allow public client flows فعال است. سپس در تب API permissions اسکوپهای موردنیاز مثل User.Read یا اسکوپهای API سفارشی خود را اضافه و در صورت لزوم Admin Consent بگیرید. Client ID و Tenant ID را از تب Overview کپی کنید. این دو مقدار قلب پیکربندی MSAL شما خواهند بود.
Redirect URI حساسترین بخش پیکربندی MSAL در MAUI است و بیش از نیمی از مشکلات «چرا صفحهی لاگین باز میشود اما هرگز به اپ برنمیگردد» ریشه در این تنظیم دارد. من در اولین اپ MAUI که MSAL را برای یک بانک ادغام کردم، دقیقاً همین باگ را داشتم و باورم نمیشد که کل روزم را صرف چیزی به سادگی یک اسکیم گمشده کنم. هر پلتفرم یک روش متفاوت برای اعلام اسکیم به سیستمعامل دارد.
اندروید
در Platforms/Android/AndroidManifest.xml این activity را داخل تگ <application> اضافه کنید:
Broker Authentication: Microsoft Authenticator و WAM
Broker یک برنامهی سیستمی جداگانه است که فرآیند احراز هویت را از اپ شما انجام میدهد. در iOS/اندروید این نقش را Microsoft Authenticator و در ویندوز Web Account Manager (WAM) بازی میکند. مزیتهای Broker کم نیست: اعمال Conditional Access، پشتیبانی از Device Compliance در Intune، دسترسی به Windows Hello و رمزنگاری کلید در Secure Enclave بهجای ذخیرهی رفرش توکن در فایل اپ.
برای فعالسازی Broker در MSAL کافی است روش WithBroker را در Builder فراخوانی کنید:
خروجی را در پرتال Entra ID، تب Authentication، بخش Android در Signature hash وارد کنید. برای build انتشار، همین کار را با keystore انتشار انجام دهید. (ما این را در پایپلاین CI/CD بهصورت خودکار میکشیم؛ دستی این کار را تکرار نکنید، چون بعد از دو سه انتشار حتماً hash انتشار را با hash دیباگ اشتباه میگیرید.)
در ویندوز، WAM بدون نیاز به نصب چیز اضافی کار میکند اما Redirect URI به فرم ms-appx-web://microsoft.aad.brokerplugin/{CLIENT_ID} میخواهد. اگر اپ MAUI شما packaged است (MSIX)، این URI بهطور خودکار توسط Windows به شما بازمیگردد. برای اپهای unpackaged باید از راهنمای رسمی WAM در Microsoft Learn پیروی کنید.
تفاوت AcquireTokenSilent و AcquireTokenInteractive
الگوی استاندارد MSAL این است که ابتدا AcquireTokenSilent فراخوانی میشود؛ اگر توکن معتبر در کش وجود داشت یا رفرش توکن هنوز اعتبار داشت، بدون تعامل کاربر برمیگردد. در غیر این صورت MsalUiRequiredException پرتاب میشود و باید به AcquireTokenInteractive برگردیم. این جداسازی به دو دلیل مهم است: کاهش تجربهی تحریککنندهی لاگینهای مکرر، و صرفهجویی در پهنای باند در شبکههای سلولی ضعیف.
public async Task<AuthenticationResult> AcquireTokenAsync()
{
var accounts = await _pca.GetAccountsAsync();
var firstAccount = accounts.FirstOrDefault();
try
{
return await _pca.AcquireTokenSilent(Scopes, firstAccount)
.ExecuteAsync();
}
catch (MsalUiRequiredException)
{
// نیاز به تعامل کاربر داریم
return await _pca.AcquireTokenInteractive(Scopes)
.WithParentActivityOrWindow(GetParentWindow())
.WithUseEmbeddedWebView(false) // مرورگر سیستمی امنتر است
.ExecuteAsync();
}
}
private object GetParentWindow()
{
#if ANDROID
return Platform.CurrentActivity;
#elif IOS
return null; // MSAL از UIApplication.SharedApplication استفاده میکند
#else
return null;
#endif
}
پارامتر WithUseEmbeddedWebView(false) باعث میشود از ASWebAuthenticationSession در iOS و Custom Tabs در اندروید استفاده شود که هم امنتر است (به کوکیهای SSO مرورگر دسترسی دارد) و هم برای اپهای عمومی توسط RFC 8252 (OAuth 2.0 for Native Apps) توصیهی رسمی است. اگر واقعاً به WebView داخلی نیاز دارید (مثلاً برای اپهای تحت وایتلیبل)، حواستان به قوانین اپ استور باشد؛ اپل بهطور فزایندهای WebViewهای داخلی برای OAuth را ریجکت میکند.
سریالسازی امن Token Cache در MAUI
بهطور پیشفرض، MSAL کش توکن را در حافظه نگه میدارد که با بسته شدن اپ از بین میرود. برای حفظ Login بین راهاندازیهای اپ، باید کش را سریالسازی و در استوریج امن پلتفرم ذخیره کنید. بستهی Microsoft.Identity.Client.Extensions.Msal این کار را روی iOS با Keychain، روی اندروید با AndroidX Security Crypto و روی ویندوز با DPAPI انجام میدهد.
using Microsoft.Identity.Client.Extensions.Msal;
private async Task ConfigureTokenCacheAsync()
{
var storageProperties = new StorageCreationPropertiesBuilder(
"msal_cache.bin",
FileSystem.AppDataDirectory)
.WithMacKeyChain("com.mycompany.myapp", "MSALCache")
.WithLinuxKeyring(
"com.mycompany.myapp",
MsalCacheHelper.LinuxKeyRingDefaultCollection,
"MSAL token cache",
new KeyValuePair<string, string>("Version", "1"),
new KeyValuePair<string, string>("Product", "MyApp"))
.Build();
var cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties);
cacheHelper.RegisterCache(_pca.UserTokenCache);
}
در iOS و اندروید مدیریت کش توسط MSAL خودکار انجام میشود و شما نیازی به کد اضافه ندارید. MSAL از Keychain در iOS و SharedPreferences رمزنگاریشده در اندروید استفاده میکند. اگر میخواهید حساسیت بالاتری داشته باشید و توکنهای حساس دیگری مثل توکنهای API سفارشی را هم بهطور امن نگهداری کنید، الگوی احراز هویت JWT با SecureStorage را با MSAL ترکیب کنید تا معماری منسجم داشته باشید.
Microsoft Entra External ID و کاربران خارجی
مایکروسافت در پایان ۲۰۲۳ اعلام کرد که Azure AD B2C برای مستأجران جدید در دسترس نیست و Microsoft Entra External ID جانشین رسمی آن است. خبر خوب برای توسعهدهندگان MAUI این است که همان کد MSAL بدون تغییر با External ID کار میکند. تنها URL Authority تغییر میکند:
External ID برخلاف B2C بهجای Policy، از User Flow و Custom Claims Provider استفاده میکند. برای سناریوهای B2B که در آن کاربر خارجی میخواهد به منابع Entra ID شما دسترسی داشته باشد، از پارامتر WithAuthority("https://login.microsoftonline.com/organizations") استفاده کنید تا هر مستأجر Entra ID را بپذیرد. این الگو در اپهای SaaS چندمستأجرهای که در حوزهی سلامت روی آنها کار کردهام بسیار پرکاربرد است.
مدیریت خطاها و Conditional Access
MSAL چند خطای مشخص را پرتاب میکند که هر کدام نیاز به رفتار متفاوت دارد. جدول زیر پرتکرارترینها را خلاصه میکند:
برای مدیریت Claims Challenge (که در Conditional Access یا Continuous Access Evaluation فعال میشود) باید WWW-Authenticate header بازگشتی از API را بخوانید و در فراخوانی بعدی MSAL از WithClaims استفاده کنید:
اگر اپ شما گزارش کرش خودکار دارد، دقت کنید که PII (Personally Identifiable Information) در پیامهای MSAL درج نشود. پارامتر enablePiiLogging: false باید همیشه در production فعال بماند. برای راهاندازی گزارشگیری کرش سازگار با MAUI میتوانید به مقالهی گزارشگیری Crash با Sentry پس از بازنشستگی App Center مراجعه کنید که فیلترهای مناسب برای حذف توکنها را نیز پوشش میدهد.
پرسشهای پرتکرار
تفاوت MSAL و OAuth چیست؟
OAuth 2.0 یک پروتکل استاندارد است در حالی که MSAL یک پیادهسازی مشخص از OAuth 2.0 و OpenID Connect برای پلتفرم هویت مایکروسافت است. MSAL علاوه بر جریانهای استاندارد OAuth، منطق کش توکن، رفرش خودکار، Broker و Conditional Access را کپسوله میکند که در سایر کتابخانههای عمومی OAuth وجود ندارد.
آیا MSAL روی MAUI iOS نیاز به Xcode جداگانهای دارد؟
خیر. MSAL.NET نسخه ۴.۶۶ بهطور کامل روی net8.0-ios و net10.0-ios کامپایل میشود و نیازی به bridge یا binding سفارشی ندارد. تنها نکته این است که Info.plist باید CFBundleURLTypes و LSApplicationQueriesSchemes را بهدرستی داشته باشد.
چگونه Broker را در اندروید فعال کنیم بدون اینکه کاربر Microsoft Authenticator نصب داشته باشد؟
اگر Authenticator نصب نباشد، MSAL بهطور خودکار به Custom Tabs مرورگر Fallback میکند. برای اجبار به Broker میتوانید در Entra ID، Conditional Access با Require compliant device فعال کنید که در آن صورت لاگین بدون Authenticator رد خواهد شد. اما برای اپهای عمومی این کار توصیه نمیشود.
آیا با MSAL میتوانم به Microsoft Graph دسترسی داشته باشم؟
بله. کافی است اسکوپ User.Read یا هر اسکوپ Graph دیگری را در آرایهی Scopes اضافه کنید. سپس AccessToken بازگشتی را در هدر Authorization: Bearer به https://graph.microsoft.com/v1.0/me ارسال کنید. بستهی Microsoft.Graph نیز میتواند مستقیماً از MSAL TokenCredential بگیرد.
Token Cache در MAUI چگونه بین راهاندازیها حفظ میشود؟
در iOS و اندروید MSAL بهطور خودکار از Keychain و AndroidX Security استفاده میکند و نیازی به کد اضافه نیست. در ویندوز و لینوکس باید از بستهی Microsoft.Identity.Client.Extensions.Msal و MsalCacheHelper برای سریالسازی امن استفاده کنید. رفرش توکن پیشفرض ۹۰ روز اعتبار دارد که در Conditional Access ممکن است کمتر شود.
Caleb has shipped seven mobile apps to the App Store and Play Store over the last nine years, four of them in Xamarin and three in .NET MAUI. He spent five years at a healthcare-tech company in Boston building a clinician-facing iPad app used by roughly 14,000 nurses, then moved to a freelance practice in 2024 focused on enterprise MAUI rollouts for regulated industries.
His writing tends toward the practical: CI pipelines on App Center successors, MSAL token caching across Android lifecycle resets, MAUI Blazor Hybrid in production, and the awkward seams between MAUI and native SDKs that vendors haven't gotten around to wrapping. He runs a small Discord for enterprise MAUI engineers and writes a Friday newsletter from his home in Portland, Maine.
راهنمای عملی پیادهسازی احراز هویت JWT در .NET MAUI — ذخیره امن توکن با SecureStorage، تزریق خودکار با DelegatingHandler، محافظت مسیرها با Shell Navigation Guard و رفرش خودکار با Polly. همراه با کد کامل و تست.