我正在为我的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.Name
为null
,表示未进行IIS身份验证。
我还尝试在Startup.cs的ConfigureServices
方法中禁用自动身份验证
services.Configure<IISOptions>(options => {options.AutomaticAuthentication = false;});
效果相同 - OpenID Connect启动,但context.HttpContext.User.Identity.Name
为null
。如果我在Kestrel上运行应用程序或在IIS站点上关闭Windows Auth,也会发生同样的情况。
有两种方法可以同时使用它 - 在可用时进行IIS身份验证,但在使用IIS为login_hint参数建立的身份时仍继续使用OpenId Connect吗?
提前致谢!
答案 0 :(得分:2)
如果我理解正确,您首先尝试进行Windows身份验证,阅读用户名并将其传递给Azure AD。
我的猜测是,如果您强制使用[Authorize(AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)]
的OIDC方案,IIS将不再为您执行IWA(集成Windows身份验证)。
以下是您可以尝试的一些事项:
至少对于经典的ASP.NET应用程序,您可以转到IIS站点仪表板,Authentication
下可以禁用“匿名身份验证”,同时启用“Windows身份验证”。这将强制用户始终使用Windows进行身份验证,并且可能不是您要查找的内容。
您可以在重定向之前在控制器操作中手动质询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。