如何使用 IdentityServer 4 实现 Windows 身份验证
Posted
技术标签:
【中文标题】如何使用 IdentityServer 4 实现 Windows 身份验证【英文标题】:How to implement Windows Authentication with IdentityServer 4 【发布时间】:2016-12-20 12:31:45 【问题描述】:如何使用 Identity Server 4 正确实施 Windows 身份验证? 有没有样品可以做到这一点?
我查看了 IdentityServer 4 的源代码,在 AccountController 的 Host 项目中,我注意到有 Windows 身份验证检查,它们是作为外部提供程序实现的,但我似乎无法完成配置.
有人用 idsrv4 成功实现了 windows 身份验证吗?
【问题讨论】:
【参考方案1】:对于在搜索结果中遇到此问题且无法将快速入门与 ASPNET Identity 快速入门相结合的任何人,这里是缺少的部分。
在大多数情况下,您希望使用 ASPNET 身份代码,利用 SignInManager 来完成繁重的工作。一旦你到达那里并从快速开始添加 Window 身份验证代码,你应该到达一切看起来都在工作的地步,但是你在回调中的这一行得到 null:
ExternalLoginInfo info = await _signInManager.GetExternalLoginInfoAsync();
要将 Windows 视为真正的外部提供程序,而不是在第 163 行附近将“方案”添加到 auth 属性中,您希望将密钥更改为“LoginProvider”:
properties.Items.Add("LoginProvider", AccountOptions.WindowsAuthenticationSchemeName);
我使用域查询来提取有关我的用户的额外信息,如下所示:
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domain))
using (UserPrincipal up = UserPrincipal.FindByIdentity(pc, wp.Identity.Name))
if (up == null)
throw new NullReferenceException($"Unable to find user: wp.Identity.Name");
id.AddClaim(new Claim(ClaimTypes.NameIdentifier, up.Sid.Value));
id.AddClaim(new Claim(JwtClaimTypes.Subject, wp.Identity.Name));
id.AddClaim(new Claim(JwtClaimTypes.Name, wp.Identity.Name));
id.AddClaim(new Claim(JwtClaimTypes.Email, up.EmailAddress));
id.AddClaim(new Claim(Constants.ClaimTypes.Upn, up.UserPrincipalName));
id.AddClaim(new Claim(JwtClaimTypes.GivenName, up.GivenName));
id.AddClaim(new Claim(JwtClaimTypes.FamilyName, up.Surname));
添加什么声明由您决定,但您需要使用 ClaimTypes.NameIdentifier 类型之一,以便 SigninManager 找到。 SID 对我来说似乎是最好的用途。最后要更改的是在第 178-181 行附近使用正确方案的 SignInAsync 调用:
await HttpContext.SignInAsync(IdentityConstants.ExternalScheme, new ClaimsPrincipal(id), properties);
除非您覆盖 IdentityServer4 在 .net core 2 中使用的默认方案,否则这是正确的默认方案。现在您在回调中调用 GetExternalLoginInfoAsync 将起作用,您可以继续!
【讨论】:
不幸的是,我摸不着头脑。我的问题是,Windows 身份验证在本地 IIS Express 中有效,但是当部署到我的机器上的完整 IIS 时,它不会。我不断收到登录弹出窗口的挑战。在 iis 中的站点上启用了 Windows 身份验证。 需要更多信息来帮助您进行故障排除,最好的猜测是 IIS 身份验证方法设置不正确,或者它无权访问您尝试进行身份验证的域。 我的问题在***.com/questions/50255110/… @Dan 你能告诉我获取 Identity.Name 的 wp 对象的类型是什么吗?? Wp 是一个 WindowsPrincipal 简单代码【参考方案2】:这里很快就会有更多文档:
https://identityserver4.readthedocs.io
但简而言之 - 从 IdentityServer 的角度来看是的,Windows 身份验证是一个外部提供程序(与 IS 本机身份验证 cookie 不同)。
您无需执行任何操作来实现 Windows 身份验证 - 只需使用支持它的主机即可。
也可以
与 IIS 集成的 Kestrel 网络监听器在这两种情况下,您都可以通过挑战Negotiate
或NTLM
的方案来调用Windows 机器。这不是特定的,而是 ASP.NET Core 的工作方式。
我们的快速启动 UI 展示了如何做到这一点 - 检查 AccountController。
https://github.com/IdentityServer/IdentityServer4.Quickstart.UI
【讨论】:
感谢您的回答和澄清。当您说“通过挑战方案来调用 Windows 机器”时,您的意思是使用 app.UseOpenIdConnectAuthentication(new OpenIdConnectOptionsAuthenticationScheme = "NTLM", ...);如果你能给我一些指导,我可以帮助你。我目前处于我实施 IS 的项目阶段,但它阻碍了其他任务的开发,因此必须快速解决 IS。此外,由于 Windows 身份验证是外部提供程序,这是否意味着我需要再拥有一个仅实现 NTLM 的 Web 应用程序? 您在 ASP.NET Core AuthenticationManager 上调用 Challenge。正如我所说 - 这不是特定的。 见这里:github.com/IdentityServer/IdentityServer4/blob/dev/src/Host/… 是否可以为 IdentityServer4 创建如下内容:github.com/IdentityServer/WindowsAuthentication? 如果您检查任何稍后设置了外部身份验证提供程序(即 google 等)的快速入门示例,则在 @leastprivilege 的基础上,如果启用了 Windows 身份验证,Windows 应自动显示为可用的身份验证方案。在 BuildLoginViewModelAsync 方法中的 AccountService 上放置一个断点,您将看到填充了 Windows 选项。当我使用 Windows 按钮登录时,与我之前注册的帐户不同,它第一次为我工作。【参考方案3】:问题:
和我一样,您可能已经完成了所有 ASP.NET Identity / IdentityServer 4 快速入门和教程,希望您的 Windows 身份验证正常工作但失败,但以下情况除外:
Exception: External authentication error
Host.Quickstart.Account.ExternalController.Callback() in ExternalController.cs, line 89
然后您可能已经发现在Callback
函数中调用HttpContext.AuthenticateAsync(...)
后result?.Succeeded
为假,其余结果属性为null
...
说明:
之所以会这样,是因为回调期间验证的身份验证方案是IdentityConstants.ExternalScheme
...
但是,在ProcessWindowsLoginAsync
函数期间,对HttpContext.SignInAsync
的调用设置为使用IdentityServerConstants.ExternalCookieAuthenticationScheme
的身份验证方案,这与回调的预期不匹配,进而导致您的Windows 身份验证尝试失败。
解决方案:
所以我们需要做的就是解决这个问题,将调用更改为HttpContext.SignInAsync
以匹配回调预期的方案:
await HttpContext.SignInAsync(IdentityConstants.ExternalScheme, new ClaimsPrincipal(id), props);
完成此操作后,您将使用 Windows 身份验证成功登录,并且您的 "victory dance" 可以开始!!!
非常感谢 Dan 的回答!
如果没有他的解决方案,我可能仍然会为此而烦恼。
Dan 还提到您应该将 Properties.Items["scheme"]
更改为 "LoginProvider"
...
然而,这是不必要的,将导致FindUserFromExternalProviderAsync
函数失败,因为它希望在"scheme"
属性中提供登录提供程序。
自从 Dan 发布他的答案后,IdentityServer 快速入门源似乎已经更新,所以我认为最好为面临同样问题的人发布更新。
【讨论】:
【参考方案4】:在您的 Identity Server 的 AccountOptions.cs
中确保 public static bool WindowsAuthenticationEnabled = true;
,我认为快速入门默认为 false
确保身份服务器的应用程序池使用具有正确凭据的帐户(我假设一个可以查询 AD 的帐户)。我无法使用内置帐户 AppPoolIdentity、LocalService 或 Network。 LocalSystem 几乎可以正常工作,但出现了另一个错误。
使用您在上面为应用程序池创建的帐户至少登录一次此 Web 服务器。此帐户不必是任何类型的管理员。在应用程序池上设置高级设置以加载配置文件。
使用在身份服务器根目录上的 IIS 中设置的匿名和 Windows 凭据,您不需要摘要或基本凭据。
【讨论】:
以上是关于如何使用 IdentityServer 4 实现 Windows 身份验证的主要内容,如果未能解决你的问题,请参考以下文章
检查用户是否已在IdentityServer 4中进行了身份验证
如何使用 IdentityServer 4 为多租户应用程序触发 admin_consent 流?
在为外部访问实现 API 的情况下对 ASP.NET Core Identity 和 IdentityServer 4 感到困惑
如何在 IdentityServer4 中创建自定义授权类型