【问题标题】:ASP.Net Core 2.0: using OpenId Connect authentication running under an IIS site that has Windows Authentication enabledASP.Net Core 2.0:使用在启用了 Windows 身份验证的 IIS 站点下运行的 OpenId Connect 身份验证
【发布时间】:2018-06-17 23:03:28
【问题描述】:

我正在为我的 ASP.Net Core 2.0 Web 应用程序实施 OpenID Connect 身份验证。该应用程序在启用了 Windows 身份验证的 IIS 站点内运行。如果用户在登录到企业网络时访问应用程序,我希望他们不必在 Azure AD 对话框中输入用户名,而是让应用程序从存储在 HttpContext 中的用户名中派生它,并且将其作为 login_hint 传递给 AD 登录链接。下面是我试图实现所需行为的代码:

services.AddAuthentication(options =>
    {
        options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    .AddOpenIdConnect(options =>
        {
            options.Authority = "https://login.microsoftonline.com/<removed>";
            options.ClientId = "<removed>";
            options.ResponseType = OpenIdConnectResponseType.IdToken;
            options.CallbackPath = "/auth/signin-callback";
            options.Events = new OpenIdConnectEvents
            {
                OnRedirectToIdentityProvider = context =>
                {

                    if(context?.HttpContext?.User?.Identity?.Name != null)
                        context.ProtocolMessage.SetParameter("login_hint", context.HttpContext.User.Identity.Name.Replace("domain\\", "") + "@domain.com");

                    return Task.FromResult(0);
                }
            };
        }
    ).AddCookie();

但是,这不起作用。只要用户点击受 [Authorize] 属性保护的控制器,框架就会发现用户已经通过 IIS 的身份验证,并且不会重定向到 Azure AD 登录。

如果我在属性中指定认证方案

[Authorize(AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)]

应用重定向到 AD 登录,但 context.HttpContext.User.Identity.Namenull,这表明 IIS 身份验证没有发生。

我还尝试在 Startup.cs 的 ConfigureServices 方法中禁用自动身份验证

services.Configure&lt;IISOptions&gt;(options =&gt; {options.AutomaticAuthentication = false;});

同样的效果——OpenID Connect 启动,但context.HttpContext.User.Identity.Namenull。如果我在 Kestrel 上运行应用程序或在 IIS 站点上关闭 Windows Auth,也会发生同样的情况。

有没有一种方法可以兼得——在可用时进行 IIS 身份验证,但在使用 IIS 为 login_hint 参数建立的身份时仍继续执行 OpenId Connect?

提前致谢!

【问题讨论】:

    标签: authentication asp.net-core openid-connect


    【解决方案1】:

    如果我理解正确,您尝试先进行 Windows 身份验证,读取用户名并将其传递给 Azure AD。

    我的猜测是,如果您使用 [Authorize(AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)] 强制使用 OIDC 方案,IIS 将不再为您执行 IWA(集成 Windows 身份验证)。

    您可以尝试以下方法:

    1. 至少对于经典的 ASP.NET 应用程序,您可以转到 IIS 站点仪表板,在 Authentication 下可以禁用“匿名身份验证”,同时启用“Windows 身份验证”。这将强制用户始终使用 Windows 进行身份验证,并且可能不是您想要的。

    2. 您可以在重定向之前在控制器操作中手动质询 Windows 身份验证。这是我的做法(Core 1.1 现在可能略有不同)。

         // Clear the existing external cookie to ensure a clean login process
          await HttpContext.Authentication.SignOutAsync(_externalCookieScheme);
      
          WindowsIdentity windowsIdentity = null;
          if (_tef4AuthenticationOptions.EnableWindowsAuthentication)
          {
              // see if windows auth has already been requested and succeeded
              var result = await HttpContext.Authentication.AuthenticateAsync(ServerConstants.WindowsScheme);
              if (result is WindowsPrincipal)
                  windowsIdentity = result.Identity as WindowsIdentity;
              else
                  return Challenge(ServerConstants.WindowsScheme);                
          }
      

    【讨论】:

    • 谢谢@mode777!方法#1 不起作用,因为正如您所指出的,Windows Auth 满足框架对身份验证的要求,并且 OIDC 身份验证永远不会启动。方法#2 很有趣。但是,我仍然不明白如何将其连接到 Startup.cs 的ConfigureServices 方法。我没有在控制器中编写任何身份验证代码,指望 [Authorize] 属性将启动,这反过来会执行 Startup.cs 中定义的身份验证。
    • 实际上,感谢您的输入,我找到了解决实际问题的方法。我会将其作为单独的答案发布,但它肯定是受到您的建议的启发,所以我也赞成您的答案。谢谢!
    【解决方案2】:

    感谢@mode777,我找到了解决方案——我将此代码添加到我的 Home 控制器中:

    var oidcAuthResult = HttpContext.AuthenticateAsync(OpenIdConnectDefaults.AuthenticationScheme).Result;
    if (oidcAuthResult.Principal == null)
       return Challenge(OpenIdConnectDefaults.AuthenticationScheme);
    

    所以,我的 Home 控制器的 Index 操作的完整代码(应用程序的默认路由)很简单:

    [Authorize]
    public IActionResult Index()
    {
            var oidcAuthResult = HttpContext.AuthenticateAsync(OpenIdConnectDefaults.AuthenticationScheme).Result;
            if (oidcAuthResult.Principal == null)
                return Challenge(OpenIdConnectDefaults.AuthenticationScheme);
    
            return View();
    }
    

    ConfigureServices 方法保持不变,就像问题中指定的那样:

    services.AddAuthentication(options =>
        {
            options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        })
        .AddOpenIdConnect(options =>
            {
                options.Authority = "https://login.microsoftonline.com/<removed>";
                options.ClientId = "<removed>";
                options.ResponseType = OpenIdConnectResponseType.IdToken;
                options.CallbackPath = "/auth/signin-callback";
                options.Events = new OpenIdConnectEvents
                {
                    OnRedirectToIdentityProvider = context =>
                    {
    
                        if(context?.HttpContext?.User?.Identity?.Name != null)
                            context.ProtocolMessage.SetParameter("login_hint", context.HttpContext.User.Identity.Name.Replace("domain\\", "") + "@domain.com");
    
                        return Task.FromResult(0);
                    }
                };
            }
        ).AddCookie();
    

    所以现在身份验证流程是这样的:

    如果应用在启用 Windows Auth 的 IIS 下运行,将满足 [Authorize] 属性,因此执行将进入 Index 操作的主体,此时它将强制通过 OIDC 和 ConfigureServices 中的代码进行身份验证将使用 Windows Auth 提供的身份来设置 login_hint。如果应用在不支持 Windows Auth(或已禁用)的服务器上运行,[Authorize] 属性将立即启用 OIDC,并且控制器中的 if 语句将阻止重定向到 AD 两次。

    完美!

    再次感谢@mode777。

    【讨论】:

      猜你喜欢
      • 2018-06-25
      • 2018-07-03
      • 1970-01-01
      • 2016-06-28
      • 2019-03-14
      • 2017-04-17
      • 1970-01-01
      • 2019-01-28
      • 2017-12-31
      相关资源
      最近更新 更多