ASP.NET MVC集成Entra登录后Request.IsAuthenticated返回false问题
OWIN集成Entra身份验证后Request.IsAuthenticated返回false的问题
在ASP.NET表单身份验证场景下使用Microsoft OWIN Cookie身份验证时,Request.IsAuthenticated会正常返回true。但集成Entra(原Azure AD)身份验证后,尽管登录流程能成功完成且可以获取到用户详情,Request.IsAuthenticated仍返回false。
相关代码
public partial class Startup { private static string clientId = ConfigurationManager.AppSettings["AzureAd:ClientId"]; private static string tenant = ConfigurationManager.AppSettings["AzureAd:TenantId"]; private static string clientSecret = ConfigurationManager.AppSettings["AzureAd:ClientSecret"]; private static string authority = $"https://login.microsoftonline.com/common/v2.0"; private static string redirectUri = ConfigurationManager.AppSettings["AzureAd:RedirectUri"]; private static string returnUri = ConfigurationManager.AppSettings["AzureAd:ReturnUri"]; private static string graphScopes = ConfigurationManager.AppSettings["AzureAd:AppScope"]; public void ConfigureAuth(IAppBuilder app) { try { app.CreatePerOwinContext(ApplicationDbContext.Create); app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create); app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType); app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new Microsoft.Owin.PathString("/Account/Login"), Provider = new CookieAuthenticationProvider { OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>( validateInterval: TimeSpan.FromMinutes(30), regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) } }); app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5)); app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie); app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions { ClientId = clientId, Authority = authority, Scope = $"openid email profile offline_access User.Read Calendars.Read", RedirectUri = redirectUri, PostLogoutRedirectUri = redirectUri, TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, IssuerValidator = (issuer, token, tvp) => { return issuer; } }, Notifications = new OpenIdConnectAuthenticationNotifications { AuthenticationFailed = OnAuthenticationFailedAsync, AuthorizationCodeReceived = OnAuthorizationCodeReceivedAsync } }); var cookieOptions = new CookieAuthenticationOptions(); cookieOptions.CookieManager = new SystemWebCookieManager(); app.UseCookieAuthentication(cookieOptions); } catch (Exception ex) { Logger.Log($"/Home/Error?debug={ex.Message}"); throw ex; } } private async Task OnAuthorizationCodeReceivedAsync(AuthorizationCodeReceivedNotification notification) { notification.HandleCodeRedemption(); var idClient = ConfidentialClientApplicationBuilder.Create(clientId) .WithRedirectUri(redirectUri) .WithClientSecret(clientSecret) .Build(); var signedInUser = new ClaimsPrincipal(notification.AuthenticationTicket.Identity); HttpContext context = HttpContext.Current; var tokenStore = new SessionTokenStore(idClient.UserTokenCache, context, signedInUser); try { string[] scopes = graphScopes.Split(' '); var result = await idClient.AcquireTokenByAuthorizationCode( scopes, notification.Code).ExecuteAsync(); var userDetails = await GraphHelper.GetUserDetailsAsync(result.AccessToken); tokenStore.SaveUserDetails(userDetails); notification.HandleCodeRedemption(null, result.IdToken); } catch (MsalException ex) { string message = "AcquireTokenByAuthorizationCodeAsync threw an exception"; notification.HandleResponse(); Logger.Log($"/Home/Error?message={message}&debug={ex.Message}"); //notification.Response.Redirect($"/Home/Error?message={message}&debug={ex.Message}"); } catch (Microsoft.Graph.ServiceException ex) { string message = "GetUserDetailsAsync threw an exception"; notification.HandleResponse(); Logger.Log($"/Home/Error?message={message}&debug={ex.Message}"); //notification.Response.Redirect($"/Home/Error?message={message}&debug={ex.Message}"); } } private static Task OnAuthenticationFailedAsync(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification) { notification.HandleResponse(); string redirect = $"/Home/Error?message={notification.Exception.Message}"; if (notification.ProtocolMessage != null && !string.IsNullOrEmpty(notification.ProtocolMessage.ErrorDescription)) { redirect += $"&debug={notification.ProtocolMessage.ErrorDescription}"; } notification.Response.Redirect(redirect); return Task.FromResult(0); } }
问题原因及修复方案
1. 移除重复的Cookie身份验证中间件
代码末尾额外注册了无配置的Cookie中间件,会干扰之前的应用Cookie配置。将SystemWebCookieManager整合到第一个Cookie中间件配置中,并删除重复注册:
// 修改第一个Cookie中间件 app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new Microsoft.Owin.PathString("/Account/Login"), Provider = new CookieAuthenticationProvider { OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>( validateInterval: TimeSpan.FromMinutes(30), regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) }, CookieManager = new SystemWebCookieManager() // 新增这一行 }); // 删除以下重复代码 // var cookieOptions = new CookieAuthenticationOptions(); // cookieOptions.CookieManager = new SystemWebCookieManager(); // app.UseCookieAuthentication(cookieOptions);
2. 添加外部身份到应用身份的转换逻辑
Entra登录生成的是外部身份,需要转换为应用Cookie身份才能让Request.IsAuthenticated返回true。在OpenIdConnectAuthenticationOptions的Notifications中添加SecurityTokenValidated处理:
Notifications = new OpenIdConnectAuthenticationNotifications { AuthenticationFailed = OnAuthenticationFailedAsync, AuthorizationCodeReceived = OnAuthorizationCodeReceivedAsync, SecurityTokenValidated = async (context) => { var externalIdentity = context.AuthenticationTicket.Identity; // 可根据需求添加自定义声明 // externalIdentity.AddClaim(new Claim("CustomClaim", "Value")); var signInManager = context.OwinContext.Get<ApplicationSignInManager>(); await signInManager.SignInAsync(null, null, externalIdentity, isPersistent: false); context.HandleResponse(); context.Response.Redirect("/"); } }
3. 修正HandleCodeRedemption的调用方式
OnAuthorizationCodeReceivedAsync中重复调用HandleCodeRedemption会导致身份票证生成异常,移除第一个无参数调用:
private async Task OnAuthorizationCodeReceivedAsync(AuthorizationCodeReceivedNotification notification) { // 移除这一行:notification.HandleCodeRedemption(); var idClient = ConfidentialClientApplicationBuilder.Create(clientId) .WithRedirectUri(redirectUri) .WithClientSecret(clientSecret) .Build(); // 其余代码保持不变 }
4. 简化Issuer验证逻辑
当前自定义IssuerValidator未做实际验证,可移除该配置使用默认逻辑:
TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true // 移除IssuerValidator配置 }
内容的提问来源于stack exchange,提问作者thilim9
相关产品推荐
相关产品推荐

