ASP.Net Core 2.0:使用在启用了Windows身份验证的IIS站点下运行的OpenId Connect身份验证

时间:2018-01-08 22:59:00

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

我正在为我的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<IISOptions>(options => {options.AutomaticAuthentication = false;});

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

有两种方法可以同时使用它 - 在可用时进行IIS身份验证,但在使用IIS为login_hint参数建立的身份时仍继续使用OpenId Connect吗?

提前致谢!

2 个答案:

答案 0 :(得分:2)

如果我理解正确,您首先尝试进行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);                
        }
    

答案 1 :(得分:0)

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

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

因此,我的家庭控制器的索引操作的完整代码(应用程序的默认路由)就是:

[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身份验证的服务器上运行(或已禁用),则[授权]属性将立即启用OIDC,控制器中的if语句将阻止重定向到AD两次。 / p>

完美!

再次感谢@ mode777。