同一Azure注册应用下,Angular生成的MSAL令牌如何让ASP.NET Core MVC复用身份验证
解决方案:Azure AD 跨应用共享登录状态
方案一:利用Azure AD原生SSO会话
这是最推荐的方案,依赖Azure AD在浏览器中设置的域级别SSO cookie,让MVC应用自动识别已登录状态:
- 配置ASP.NET Core MVC的OpenID Connect中间件,确保和Angular应用使用同一个Azure注册应用的ClientId、Authority,同时启用必要参数:
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApp(options => { Configuration.Bind("AzureAd", options); options.UseTokenLifetime = true; // 沿用Azure AD的令牌有效期 options.SaveTokens = true; // 保存令牌供后续API调用使用 options.ResponseType = "code"; // 使用授权码流程,和MSAL推荐流程对齐 }); services.AddAuthorization(options => { options.FallbackPolicy = options.DefaultPolicy; // 默认要求所有页面认证 });
- 工作逻辑:用户在Angular端登录后,Azure AD会在浏览器写入
ESTSAUTH等SSO cookie。当MVC应用发起认证请求时,Azure AD检测到该cookie,会自动跳过凭证输入步骤,直接返回认证结果,MVC应用据此创建本地登录会话。
方案二:Angular传递授权码给MVC应用(适用于跨域场景)
如果两个应用不在同一域,可通过授权码传递实现无感知登录:
- Angular端用MSAL获取授权码(注意不要直接传ID令牌,避免泄露风险),导航到MVC的指定回调页面时携带授权码参数;
- MVC端接收授权码后,向Azure AD令牌端点交换成自身的ID/访问令牌,然后创建本地登录会话:
[HttpGet("signin-from-angular")] public async Task<IActionResult> SignInFromAngular(string code) { var tokenEndpoint = $"{Configuration["AzureAd:Authority"]}/oauth2/v2.0/token"; var formData = new Dictionary<string, string> { ["client_id"] = Configuration["AzureAd:ClientId"], ["client_secret"] = Configuration["AzureAd:ClientSecret"], ["code"] = code, ["redirect_uri"] = Url.Action("SignInFromAngular", "Account", null, Request.Scheme), ["grant_type"] = "authorization_code" }; using var client = new HttpClient(); var response = await client.PostAsync(tokenEndpoint, new FormUrlEncodedContent(formData)); if (!response.IsSuccessStatusCode) return BadRequest("令牌交换失败"); var tokenResponse = await response.Content.ReadFromJsonAsync<TokenResponse>(); // 构建用户身份并写入Cookie var claims = new List<Claim> { new(ClaimTypes.NameIdentifier, tokenResponse.IdTokenClaims["oid"]), new(ClaimTypes.Name, tokenResponse.IdTokenClaims["name"]) }; var identity = new ClaimsIdentity(claims, OpenIdConnectDefaults.AuthenticationScheme); await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity)); return RedirectToAction("Index", "Home"); }
- 安全提醒:必须用HTTPS传输,授权码要设置短有效期,同时验证请求来源的合法性,防止CSRF攻击。
方案三:共享认证Cookie(同域/子域场景)
如果两个应用部署在同域或子域下,可配置共享认证Cookie:
- MVC端配置数据保护和共享Cookie:
services.AddDataProtection() .PersistKeysToFileSystem(new DirectoryInfo(@"c:\shared-keys")) // 两个应用共用密钥存储 .SetApplicationName("YourSharedAppName"); // 统一应用名称 services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.Cookie.Domain = ".yourdomain.com"; // 子域共享时设置根域 options.Cookie.Name = ".SharedAuthCookie"; }) .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"));
- Angular端配置MSAL使用Cookie存储而非localStorage,确保SSO cookie和应用Cookie兼容:
export const msalConfig: Configuration = { auth: { clientId: 'your-client-id', authority: 'https://login.microsoftonline.com/your-tenant-id', redirectUri: 'https://angular.yourdomain.com', postLogoutRedirectUri: 'https://angular.yourdomain.com' }, cache: { cacheLocation: BrowserCacheLocation.Cookie, storeAuthStateInCookie: true } };
- 工作逻辑:同域下Cookie可跨应用访问,Azure AD的SSO会话结合共享的应用认证Cookie,实现登录状态无缝流转。
内容的提问来源于stack exchange,提问作者vinay jain
相关产品推荐
相关产品推荐

