在 IIS 上使用 IdentityServer4 进行 Windows 身份验证

问题描述

我正在尝试使用 Windows 身份验证凭据将我的本机(Winforms、控制台应用程序)客户端连接到 IIS 上托管的 Identity Server。重点是让用户通过 AD 进行身份验证,并使用这些凭据从 Identity Server(通过商业 https://commercial.abp.io/ 平台运行)获得正确的声明和角色。

编辑: 我发现这不是客户端相关的问题,因为即使直接在托管站点上我也无法使用我的外部登录名(Windows 凭据)。

这个东西在由 IISExpress 托管时在本地运行,然后我将它发布到 IIS 并在 IIS 设置中启用了匿名和 Windows 身份验证,这就是问题开始的地方。

My login screen

当我运行它并单击外部登录(Windows 凭据)按钮时,我通常会重定向https://myserver/Error?httpStatusCode=401 并且我会提示输入我的 Windows 凭据(即使我正确插入,也只需再次重复提示)。

This is where i get after clicking the button for automatic windows authentication

我有时会使用我的 Windows 凭据登录(这是目标)。使用用户名和密码登录工作正常。

在这里看到有人提到的类似问题: https://github.com/IdentityServer/IdentityServer4/issues/4937 没有任何解决方案\答案。

我的客户端基本上是来自这个 https://github.com/damienbod/AspNetCoreWindowsAuth

的示例 NativeConsolePKCEClient
static string _authority = "https://myserver/";
string redirectUri = "https://127.0.0.1:45656";

        var options = new OidcclientOptions
        {
            Authority = _authority,ClientId = "native.code",ClientSecret = "secret",RedirectUri = redirectUri,Scope = "openid profile",FilterClaims = false,browser = browser,Flow = OidcclientOptions.AuthenticationFlow.AuthorizationCode,ResponseMode = OidcclientOptions.AuthorizeResponseMode.Redirect,LoadProfile = true
        };

        _oidcclient = new Oidcclient(options); 
         var result = await _oidcclient.LoginAsync();

在服务器端启动配置服务:

        private void ConfigureAuthentication(ServiceConfigurationContext context,IConfiguration configuration)
    {
        context.Services.Configure<IISOptions>(iis =>     // IISOptions
        {
            iis.AuthenticationdisplayName = "Windows";
            iis.AutomaticAuthentication = false;
        });

        context.Services.AddAuthentication()
            .AddJwtBearer(options =>
            {
                options.Authority = configuration["AuthServer:Authority"];
                options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]); ;
                options.Audience = "ABPIdentityServer";
            });
    }

这是 ProcessWindowsLoginAsync 质询方法

        private async Task<IActionResult> ProcessWindowsLoginAsync(string returnUrl)
    {
        // see if windows auth has already been requested and succeeded
        var result = await HttpContext.AuthenticateAsync(Microsoft.AspNetCore.Server.IISIntegration.IISDefaults.AuthenticationScheme);
        if (result?.Principal is WindowsPrincipal wp)
        {
            // we will issue the external cookie and then redirect the
            // user back to the external callback,in essence,tresting windows
            // auth the same as any other external authentication mechanism
            var props = new AuthenticationProperties()
            {
                RedirectUri = "./ExternalLoginCallback",Items =
                {
                    { "returnUrl",returnUrl },{ "scheme",Microsoft.AspNetCore.Server.IISIntegration.IISDefaults.AuthenticationScheme },}
            };

            var id = new ClaimsIdentity(Microsoft.AspNetCore.Server.IISIntegration.IISDefaults.AuthenticationScheme);
            id.AddClaim(new Claim(JwtClaimTypes.Subject,wp.Identity.Name));
            id.AddClaim(new Claim(JwtClaimTypes.Name,wp.Identity.Name));

            // add the groups as claims -- be careful if the number of groups is too large
            {
                var wi = (WindowsIdentity)wp.Identity;
                var groups = wi.Groups.Translate(typeof(NTAccount));
                var roles = groups.Select(x => new Claim(JwtClaimTypes.Role,x.Value));
                id.AddClaims(roles);
            }

            await HttpContext.SignInAsync(IdentityConstants.ExternalScheme,new ClaimsPrincipal(id),props);
            return Redirect(props.RedirectUri);
        }
        else
        {
            // trigger windows auth
            // since windows auth don't support the redirect uri,// this URL is re-triggered when we call challenge
            return Challenge("Windows");
        }
    }

我怀疑在调用 Challenge 时这段代码会以某种方式返回重定向错误页面,但我不确定,我现在知道为什么。

那我错过了什么?是否可以在 IIS 上同时运行 Windows 和匿名身份验证?

在这里我也发现了类似的问题: identity server 4 windows authentication

但所提供的答案对我没有帮助。

解决方法

我强烈怀疑这不是客户端问题,而是令牌提供者的问题(不是 ID4 库,而是您安装了 ID4 库的库)。

我相信您已经在 AccountController->Login 操作中添加了以下代码,但是确保您已在其中添加了成功检查,如果您错过了,那么您的应用程序将进入无限循环

[HttpGet] public async Task<IActionResult> Login(string returnUrl)
{
 if(loginViewModel.ExternalLoginScheme == "Windows")
 {
   var authenticationResult = await HttpContext.AuthenticateAsync("Windows").ConfigureAwait(false);
   if (authenticationResult.Succeeded && authenticationResult?.Principal is WindowsPrincipal windowsPrinciple)
   {
     // Add your custom code here
     var authProps = new AuthenticationProperties()
                {
                    RedirectUri = Url.Action("Callback"),Items =
                    {
                        { "returnUrl",returnUrl },{ "scheme","Windows"},}
                };

    await HttpContext.SignInAsync();

    return Redirect(RedirectUri);
   }
   else
   {
     return Challenge("Windows");
   }
  }
}

我希望这能帮助您解决问题。 快乐编码!!

,

仅供可能感兴趣的任何人使用。我找到了导致重定向错误的原因。

它与我用于生成基本应用程序的 ABP 套件有某种联系。 在 ApplicationInitialization 中有一个中间件叫做

app.UseErrorPage();

当 Windows 凭据受到质疑时,哪个将其视为错误并重定向到 https://myserver/Error?httpStatusCode=401。

我不确定这个中间件是如何工作的以及为什么有时登录会起作用,但删除这部分解决了我的问题。

我希望这对某人有所帮助,不知何故,有时..