如何使用IdentityServer 4实现Windows身份验证

时间:2016-12-20 12:31:46

标签: iis asp.net-core identityserver4

如何使用Identity Server 4正确实施Windows身份验证? 有没有样品可以做到这一点?

我查看了IdentityServer 4的源代码,在AccountController的Host项目中,我注意到有Windows身份验证检查,它们是作为外部提供程序实现的。但我似乎无法工作配置。 有人用idsrv4成功实现了Windows身份验证吗?

4 个答案:

答案 0 :(得分:6)

对于在搜索结果中遇到此问题的人来说,快速入门与ASPNET身份快速入门一起遇到问题,以下是缺失的部分。

在大多数情况下,您希望使用ASPNET身份代码,利用SignInManager进行繁重的工作。一旦你到达那里并从快速入门添加Window auth代码,你应该到达一切看起来它正在工作的点,但你在回调中的这一行得到null:

 ExternalLoginInfo info = await _signInManager.GetExternalLoginInfoAsync();

要将Windows视为真正的外部提供程序,而不是将“scheme”添加到第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));
}

您添加的声明取决于您,但您需要为要查找的SigninManager输入ClaimTypes.NameIdentifier类型。 SID对我来说似乎是最好用的。最后要改变的是SignInAsync调用,以便在第178-181行使用正确的方案:

await HttpContext.SignInAsync(IdentityConstants.ExternalScheme, new ClaimsPrincipal(id), properties);

除非您覆盖IdentityServer4在.net core 2中使用的默认方案,否则这是正确的默认方案。现在你在回调中调用GetExternalLoginInfoAsync会有效,你可以继续!

答案 1 :(得分:5)

这里将会有更多文档:

https://identityserver4.readthedocs.io

但简而言之 - 是的,从IdentityServer的角度来看,Windows身份验证是外部提供程序(而不是IS本机身份验证cookie)。

您无需执行任何操作来实现Windows身份验证 - 只需使用支持它的主机即可。

那是

  • 与IIS集成的Kestrel
  • WebListener

在这两种情况下,您都可以通过挑战NegotiateNTLM的方案来调用Windows机制。这不是特定于IS的 - 但是ASP.NET Core的工作方式。

我们的快速入门UI显示了如何执行此操作 - 检查AccountController。

https://github.com/IdentityServer/IdentityServer4.Quickstart.UI

答案 2 :(得分:0)

在您的Identity Server的AccountOptions.cs中确保public static bool WindowsAuthenticationEnabled = true;,我认为快速入门默认为false

确保您的身份服务器的应用池使用的是具有正确凭据的帐户(我假设一个可以查询AD的帐户)。我无法使用内置帐户AppPoolIdentity,LocalService或Network。 LocalSystem几乎可以工作,但是又出现了另一个错误。

使用您在上面针对应用程序池创建的帐户,至少登录此Web服务器一次。此帐户不必是任何类型的管理员。在应用程序池上设置高级设置以加载配置文件。

在Identity Server的根目录中使用IIS中设置的匿名和Windows凭据,您不需要摘要或基本。

答案 3 :(得分:0)

问题:

就像我一样,您可能在遵循所有ASP.NET Identity / IdentityServer 4快速入门和教程之后可能就到这里了,以期使Windows身份验证正常运行,但会失败,但以下情况除外:

Exception: External authentication error
    Host.Quickstart.Account.ExternalController.Callback() in ExternalController.cs, line 89

result?.Succeeded函数中调用HttpContext.AuthenticateAsync(...)之后,您可能发现Callback为假,其余结果属性为null ... < / p>


说明:

这样做的原因是由于在回调过程中验证的身份验证方案为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快速入门源似乎已更新,所以我认为最好为面临相同问题的人员发布更新。