如何使用 IdentityServer 4 实现 Windows 身份验证
How to implement Windows Authentication with IdentityServer 4
如何使用 Identity Server 4 正确实施 Windows 身份验证?
有没有样本可以做到这一点?
我查看了 IdentityServer 4 的源代码,在 AccountController 的主机项目中,我注意到有 Windows 身份验证检查,它们是作为外部提供程序实现的,但我不能似乎可以解决配置问题。
有人成功实施了 windows idsrv4 身份验证吗?
这里很快就会有更多文档:
https://identityserver4.readthedocs.io
但简而言之 - 从 IdentityServer 的角度来看是的 Windows 身份验证是一个外部提供者(与 IS 本机身份验证 cookie 相对)。
您无需执行任何操作即可实施 Windows 身份验证 - 只需使用支持它的主机即可。
也就是
- Kestrel 与 IIS 集成
- WebListener
在这两种情况下,您都可以通过挑战 Negotiate
或 NTLM
的方案来调用 Windows 机制。这不是特定的 - 但 ASP.NET Core 的工作方式。
我们的快速入门 UI 展示了如何做到这一点 - 检查 AccountController。
https://github.com/IdentityServer/IdentityServer4.Quickstart.UI
在您的身份服务器的 AccountOptions.cs
中确保 public static bool WindowsAuthenticationEnabled = true;
,我认为快速入门默认为 false
确保您的身份服务器应用程序池使用的是具有适当凭据的帐户(我假设是一个可以查询 AD 的帐户)。我无法使用内置帐户 AppPoolIdentity、LocalService 或 Network。 LocalSystem 几乎可以正常工作,但由于另一个错误。
使用您在上面为应用程序池创建的帐户至少登录一次此 Web 服务器。此帐户不必是任何类型的管理员。在应用程序池上设置高级设置以加载配置文件。
使用身份服务器根目录下的 IIS 中设置的匿名和 Windows 凭据,不需要摘要或基本。
对于在搜索结果中遇到此问题且无法将快速入门与 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 对我来说似乎是最好的用途。最后要更改的是 SignInAsync 调用,以在第 178-181 行附近使用正确的方案:
await HttpContext.SignInAsync(IdentityConstants.ExternalScheme, new ClaimsPrincipal(id), properties);
除非您要覆盖 IdentityServer4 在 .net core 2 中使用的默认方案,否则这是正确的默认方案。现在您在回调中对 GetExternalLoginInfoAsync 的调用将起作用,您可以继续!
问题:
像我一样,您可能在遵循了所有 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 post 编辑他的回答以来,IdentityServer 快速启动源似乎已经更新,所以我认为最好 post 为面临同样问题的人更新。
如何使用 Identity Server 4 正确实施 Windows 身份验证? 有没有样本可以做到这一点?
我查看了 IdentityServer 4 的源代码,在 AccountController 的主机项目中,我注意到有 Windows 身份验证检查,它们是作为外部提供程序实现的,但我不能似乎可以解决配置问题。
有人成功实施了 windows idsrv4 身份验证吗?
这里很快就会有更多文档:
https://identityserver4.readthedocs.io
但简而言之 - 从 IdentityServer 的角度来看是的 Windows 身份验证是一个外部提供者(与 IS 本机身份验证 cookie 相对)。
您无需执行任何操作即可实施 Windows 身份验证 - 只需使用支持它的主机即可。
也就是
- Kestrel 与 IIS 集成
- WebListener
在这两种情况下,您都可以通过挑战 Negotiate
或 NTLM
的方案来调用 Windows 机制。这不是特定的 - 但 ASP.NET Core 的工作方式。
我们的快速入门 UI 展示了如何做到这一点 - 检查 AccountController。
https://github.com/IdentityServer/IdentityServer4.Quickstart.UI
在您的身份服务器的 AccountOptions.cs
中确保 public static bool WindowsAuthenticationEnabled = true;
,我认为快速入门默认为 false
确保您的身份服务器应用程序池使用的是具有适当凭据的帐户(我假设是一个可以查询 AD 的帐户)。我无法使用内置帐户 AppPoolIdentity、LocalService 或 Network。 LocalSystem 几乎可以正常工作,但由于另一个错误。
使用您在上面为应用程序池创建的帐户至少登录一次此 Web 服务器。此帐户不必是任何类型的管理员。在应用程序池上设置高级设置以加载配置文件。
使用身份服务器根目录下的 IIS 中设置的匿名和 Windows 凭据,不需要摘要或基本。
对于在搜索结果中遇到此问题且无法将快速入门与 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 对我来说似乎是最好的用途。最后要更改的是 SignInAsync 调用,以在第 178-181 行附近使用正确的方案:
await HttpContext.SignInAsync(IdentityConstants.ExternalScheme, new ClaimsPrincipal(id), properties);
除非您要覆盖 IdentityServer4 在 .net core 2 中使用的默认方案,否则这是正确的默认方案。现在您在回调中对 GetExternalLoginInfoAsync 的调用将起作用,您可以继续!
问题:
像我一样,您可能在遵循了所有 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 post 编辑他的回答以来,IdentityServer 快速启动源似乎已经更新,所以我认为最好 post 为面临同样问题的人更新。