.NET Core中ADFS认证授权实现及相关技术问题咨询
现有实现代码
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString)); builder.Services.AddDatabaseDeveloperPageExceptionFilter(); builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>(); builder.Services.AddAuthentication(sharedOptions => { sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme; }) .AddWsFederation(options => { options.Wtrealm = "urn:DevTest"; options.MetadataAddress = "https://example.com/FederationMetadata/2007-06/FederationMetadata.xml"; options.Wreply = "https://localhost:44341/Home/Index/"; }) .AddCookie();
核心问题
- 如果需要使用Claims,ASP.NET Identity是否是必需项?(当前获取Claims的代码如下)
ClaimsIdentity id = ((ClaimsIdentity)User.Identity); var claim = id.FindFirst(ClaimTypes.Email);
- 遇到
IsAuthenticated返回false的问题:- 相同配置在另一ASP.NET MVC应用中正常工作
- 排查发现ADFS服务器未配置NameID claim,是否会导致认证失败?
- ClaimsIdentity的
IsAuthenticated属性基于AuthenticationType值判断,当前该值为null,是否因缺少NameID claim导致?(ClaimsIdentity源码如下)
public virtual bool IsAuthenticated { get { return !string.IsNullOrEmpty(_authenticationType); } }
- 能否提供ADFS认证与基于Claims的授权的示例实现?
问题1:使用Claims是否必须依赖ASP.NET Identity?
不需要。ASP.NET Identity是一套包含用户存储、角色管理的用户管理系统,但Claims是ASP.NET Core认证系统的核心组成部分,所有基于标准认证协议(如WsFederation、OpenID Connect)的认证方式都会自动生成ClaimsIdentity,完全无需依赖ASP.NET Identity。
你当前代码中同时添加了ASP.NET Identity和WsFederation认证,两者可以共存,但如果只需要ADFS认证和Claims操作,完全可以移除AddDefaultIdentity相关代码,不会影响Claims的获取与使用。
问题2:IsAuthenticated返回false的原因分析
(1)NameID claim缺失是否导致认证失败?
NameID是ADFS默认的用户唯一标识Claim,但它不会直接导致认证失败——ADFS仍会完成认证流程,只是返回的Claims集合中没有NameID。部分认证中间件可能期望存在唯一标识用户的Claim,可能影响后续Cookie生成,但不是IsAuthenticated为false的直接原因。
(2)AuthenticationType为null的原因
IsAuthenticated返回false的直接原因是AuthenticationType为null,这通常是因为认证中间件未正确设置ClaimsIdentity的认证类型。在WsFederation认证流程中,中间件应自动将AuthenticationType设置为WsFederationDefaults.AuthenticationScheme(即"WsFederation")。
常见触发原因:
- WsFederation配置错误:比如
MetadataAddress无法访问、Wtrealm与ADFS中信赖方标识符不匹配 - 认证流程未完整执行:用户未完成ADFS登录跳转,或回调后中间件未正确处理响应生成
ClaimsIdentity - 配置冲突:代码中重复调用
AddCookie,WsFederation已隐式依赖Cookie处理,单独调用可能导致配置冲突
问题3:ADFS认证与基于Claims授权的示例实现
(1)简化认证配置(移除ASP.NET Identity)
builder.Services.AddAuthentication(sharedOptions => { sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme; }) .AddWsFederation(options => { options.Wtrealm = "urn:DevTest"; // 必须与ADFS中信赖方标识符完全一致 options.MetadataAddress = "https://your-adfs-server/FederationMetadata/2007-06/FederationMetadata.xml"; // 回调地址可选,默认使用/signin-wsfed,若自定义需确保ADFS同步配置 // options.Wreply = "https://localhost:44341/signin-wsfed"; }) .AddCookie(); // 如需自定义Cookie配置可在此调整,WsFederation已依赖Cookie处理
(2)获取Claims并处理
在Controller中获取Claims:
public IActionResult Index() { if (User.Identity is ClaimsIdentity claimsIdentity) { var emailClaim = claimsIdentity.FindFirst(ClaimTypes.Email); var nameClaim = claimsIdentity.FindFirst(ClaimTypes.Name); // 业务逻辑处理 } return View(); }
(3)基于Claims的授权策略配置
在Program.cs中定义授权策略:
builder.Services.AddAuthorization(options => { options.AddPolicy("RequireEmail", policy => policy.RequireClaim(ClaimTypes.Email)); options.AddPolicy("AdminOnly", policy => policy.RequireClaim("Role", "Admin")); // 需确保ADFS返回对应Role类型Claim });
在Controller/Action上应用策略:
[Authorize(Policy = "RequireEmail")] public IActionResult SecurePage() { return View(); } [Authorize(Policy = "AdminOnly")] public IActionResult AdminPanel() { return View(); }
(4)ADFS端配置注意事项
- 确保信赖方标识符与代码中
Wtrealm完全匹配 - 配置ADFS向信赖方发送必要的Claims(如Email、Name、Role等)
- 确保ADFS元数据地址可被应用正常访问
针对当前问题的排查建议
- 移除代码中多余的
AddDefaultIdentity和单独的AddCookie调用,简化认证配置 - 核对ADFS中信赖方的配置:
Wtrealm是否匹配,是否配置了要发送的Claims - 开启认证日志排查中间件执行过程:
builder.Logging.AddFilter("Microsoft.AspNetCore.Authentication", LogLevel.Debug);
- 确认用户完成ADFS登录流程,回调地址与ADFS配置一致
内容的提问来源于stack exchange,提问作者Nina

