Asp.Net Core结合AzureAD外部登录时Identity角色验证失效问题
问题:Azure AD外部登录结合ASP.NET Core Identity后角色授权失效
系统原本使用Azure AD作为外部登录提供商,Program.cs配置如下:
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
appsettings.json已正确配置clientId、tenantId等参数,运行正常。
为限制仅特定用户访问,引入ASP.NET Core Identity,创建用户管理页面从AD搜索添加用户并分配Admin等角色。通过添加登录登出的Scaffolded Item解决了初始的Identity与外部登录不兼容问题。
编写CheckSignIn方法用于用户AD登录后验证系统内是否存在该用户:
[HttpGet] public async Task<IActionResult> CheckSignIn() { if (User.Identity.IsAuthenticated) { var user = await userManager.FindByEmailAsync(User.Identity.Name); if (user != null) { await signInManager.SignInAsync(user, false); return RedirectToAction("Dashboard", "Dashboard"); } else { await signInManager.SignOutAsync(); return RedirectToAction("NoAccess", "ManageAccess"); } } return RedirectToAction("NoAccess", "ManageAccess"); }
当前问题:给用户分配Admin角色后,带有[Authorize(Roles="Admin")]的控制器会将用户重定向到访问拒绝页;调用SignInManager.IsSignedIn(user)返回false,系统无法识别用户登录状态及角色权限。
解决方案
1. 修正认证Scheme的优先级配置
同时使用Azure AD和Identity时,需明确设置默认认证、挑战和登录Scheme,确保Identity的Cookie认证为核心,Azure AD作为外部登录提供商。修改Program.cs:
// 先注册Identity服务 builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = false) .AddRoles<IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>(); // 配置认证及Azure AD外部登录 builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; options.DefaultSignInScheme = IdentityConstants.ExternalScheme; }) .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
2. 完善CheckSignIn的登录逻辑
原方法仅创建Identity会话但未合并Azure AD Claims、加载用户角色,调整如下:
[HttpGet] public async Task<IActionResult> CheckSignIn() { if (User.Identity.IsAuthenticated) { // 获取外部登录信息 var externalLoginInfo = await signInManager.GetExternalLoginInfoAsync(); if (externalLoginInfo == null) { await signInManager.SignOutAsync(); return RedirectToAction("NoAccess", "ManageAccess"); } var user = await userManager.FindByEmailAsync(User.Identity.Name); if (user != null) { // 关联外部登录并创建Identity会话 var signInResult = await signInManager.ExternalLoginSignInAsync( externalLoginInfo.LoginProvider, externalLoginInfo.ProviderKey, isPersistent: false, bypassTwoFactor: true); if (signInResult.Succeeded) { // 加载用户角色与Claims并更新认证主体 var roles = await userManager.GetRolesAsync(user); var userClaims = await userManager.GetClaimsAsync(user); var identity = new ClaimsIdentity(IdentityConstants.ApplicationScheme); identity.AddClaims(userClaims); foreach (var role in roles) { identity.AddClaim(new Claim(ClaimTypes.Role, role)); } // 追加Azure AD中未重复的Claims(可选) identity.AddClaims(User.Claims.Where(c => !userClaims.Any(uc => uc.Type == c.Type))); await HttpContext.SignInAsync(IdentityConstants.ApplicationScheme, new ClaimsPrincipal(identity)); return RedirectToAction("Dashboard", "Dashboard"); } } await signInManager.SignOutAsync(); return RedirectToAction("NoAccess", "ManageAccess"); } return RedirectToAction("NoAccess", "ManageAccess"); }
3. 确保角色Claims被正确注入
注册自定义Claims工厂,保证用户角色被添加到认证主体中:
// 自定义Claims工厂类 public class CustomUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser, IdentityRole> { public CustomUserClaimsPrincipalFactory( UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager, IOptions<IdentityOptions> optionsAccessor) : base(userManager, roleManager, optionsAccessor) { } protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user) { var identity = await base.GenerateClaimsAsync(user); var roles = await UserManager.GetRolesAsync(user); foreach (var role in roles) { identity.AddClaim(new Claim(ClaimTypes.Role, role)); } return identity; } } // 在Program.cs中注册 builder.Services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, CustomUserClaimsPrincipalFactory>();
4. 验证Authorize属性的Scheme配置
确保控制器的授权属性使用Identity的Scheme,而非Azure AD的Scheme:
// 正确示例:使用Identity的Application Scheme [Authorize(Roles = "Admin", AuthenticationSchemes = IdentityConstants.ApplicationScheme)] // 或依赖默认配置(已设置DefaultAuthenticateScheme为Identity Scheme) [Authorize(Roles = "Admin")]
5. 确认用户角色已正确保存
检查数据库AspNetUserRoles表,确认目标用户与Admin角色的关联记录存在;也可通过代码验证:
var user = await userManager.FindByEmailAsync("目标用户邮箱"); var assignedRoles = await userManager.GetRolesAsync(user); // 输出assignedRoles确认包含Admin
内容的提问来源于stack exchange,提问作者Ghezlan
相关产品推荐
相关产品推荐

