在 ASP.NET Core 应用程序中启用 Windows 身份验证和匿名身份验证

问题描述 投票:0回答:6

我知道这个问题之前已经被问过很多次了,但不幸的是不是关于 ASP.NET Core Web 应用程序,而是关于经典的 ASP.NET Web 应用程序。我在互联网上找到的所有答案都对我没有帮助,因为 ASP.NET Core 应用程序的 IIS 配置与经典 ASP.NET 非常不同。例如,ASP.NET Core 使用了 Kestrel 代理,因此 ASP.NET 中相关的很多配置在 ASP.NET Core 中都没有。我基本上已经尝试了在互联网上可以找到的所有内容,但没有一个对我有帮助。我希望它就像在 IIS 中的应用程序上启用匿名和 Windows 身份验证一样简单,仅此而已,但我想它会比这更有效。

在单个 ASP.NET Core Web 应用程序中启用这两种身份验证的过程是什么?

c# authentication asp.net-core iis-8 kestrel-http-server
6个回答
28
投票

IIS 将充当反向代理,负责设置并向 Kestrel 传输用户的 Windows 身份。首先,设置 IIS 以允许 Windows 和匿名身份验证:

enter image description here

然后,您需要更改 web.config 以要求 IIS 将 Windows 身份(如果找到)传输到您的 ASP.NET Core 应用程序,如下所示:https://stackoverflow.com/a/42163175/6827240

此时,如果您创建具有“[Authorize]”属性的控制器操作,则

HttpContext.User.Identity.Name;
应具有客户端使用的 Windows 标识的值。我在这里回复了类似的内容:NTLMauthentication on Specific Route in ASP.NET Core

好处是,如果您的客户端不传递 Windows 身份令牌,标准控制器操作仍然有效,而受保护的操作(使用 [Authorize] 标签)将会失败。

PS:我喜欢在详细模式下使用curl.exe来查看授权协议方面发生的情况(协商协议、NTLM令牌...)


20
投票

我对 ASP.NET Core 2.0 应用程序有类似的场景(在整个应用程序中使用 Windows 身份验证,除了单个控制器),而 Daboul 的解释还不够。

我必须按照此处所示设置自定义中间件,因为匿名优先

中间件

public class NtlmAndAnonymousSetupMiddleware
{
    private readonly RequestDelegate next;

    public NtlmAndAnonymousSetupMiddleware(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        if (context.User.Identity.IsAuthenticated || context.Request.Path.ToString().StartsWith("/Anonymous"))
        {
            await next(context);
            return;
        }

        await context.ChallengeAsync("Windows");
    }

}

及其在 Startup.cs 中的用法:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseMiddleware<NtlmAndAnonymousSetupMiddleware>();

    // other code here
}

因此,中间件仅接受 AnonymousController 的匿名请求,如果未提供 Windows 身份验证信息,则会提供质询。

匿名控制者

由于中间件区分了匿名和需要身份验证的内容,因此这看起来就像任何普通控制器一样:

[Route("Anonymous")]
public class AnonymousController : Controller
{
    [HttpGet("Echo")]
    public string Echo(string data)
    {
        return data;
    }
}

测试

(全部在Windows机器上完成)

  1. Chrome + 访问非匿名控制器操作 => 工作正常(

    @User.Identity.Name
    @Context.User.Identity.Name
    都返回正确的用户

  2. Chrome + 匿名操作 => 直接工作

  3. Firefox(不直接从操作系统传输 NTLM 票证)+非匿名 => 模式要求用户/密码 => 如果提供正确,则可以正常工作

  4. Firefox + 匿名操作 => 直接工作


8
投票

如果有人想知道,我修改了 @Alexei 的答案以使用属性而不是 Netcore 3.X 中的请求路径

首先创建类并获取端点元数据

public class NtlmAndAnonymousSetupMiddleware
{
    private readonly RequestDelegate next;

    public NtlmAndAnonymousSetupMiddleware(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task Invoke(HttpContext context)
    {

        if (context.User.Identity.IsAuthenticated || HasAnonymousAttribute(context))
        {
            await next(context);
            return;
        }

        await context.ChallengeAsync("Windows");
    }

    private bool HasAnonymousAttribute(HttpContext context)
    {
        var endpoint = context.GetEndpoint();
        var retVal = (endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != null);

        return retVal;
    }
}

然后修改 public voidConfigure(IApplicationBuilder app, IWebHostEnvironment env)

        app.UseAuthentication();
        app.UseAuthorization();
        app.UseMiddleware<NtlmAndAnonymousSetupMiddleware>();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
            endpoints.MapControllers();
        });

2
投票

我有一个在 IIS 上禁用 Windows 身份验证的解决方案。您所需要做的就是 NTLM 身份验证。只需将此递归代码放入控制器登录操作中即可:

var result = await HttpContext.AuthenticateAsync(IISDefaults.AuthenticationScheme);
        if (!result.Succeeded) {
            await HttpContext.ChallengeAsync(IISDefaults.AuthenticationScheme); //performs NTLM handshake
            return StatusCode(Response.StatusCode);  // sends 401
        }

        // windows login has already succeed
        // get user name and domain
        WindowsIdentity winIdentity = (WindowsIdentity)result.Principal.Identity;

......等等


0
投票

当 IIS 不受我们控制时(可能是一种罕见的情况),并且我们不知道是否启用了 Windows 身份验证,先前的解决方案将不起作用,因为在我们到达端点之前会引发异常。

以下方法(既不优雅也不高效)在这种情况下可能会有所帮助。这个想法基本上是触发对端点的另一个调用,以确定用户是否实际上是 Windows 日志记录者。如果此调用成功,那么我们就知道我们有一个 Windows 用户,并且可以采取相应的操作,例如重定向到需要 Windows 身份验证的端点。然而,对于大多数情况,已经发布的解决方案可能是可行的方法,因为这个解决方案涵盖了边缘情况。

另请参阅:类似条目

代码示例(.Net 6):

    [HttpGet]
    [AllowAnonymous]
    public async Task<IActionResult> TestWindowsAuthAsync(CancellationToken cancellationToken)
    {
        using var client = new HttpClient(new HttpClientHandler()
        {
            UseDefaultCredentials = true
        });

        var response = await client.GetAsync($"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}{HttpContext.Request.PathBase}{HttpContext.Request.Path}/HasUserWindowsAuth");
        if (response.IsSuccessStatusCode)
        {
            // Yes, now we know that user indeed has windows authentication and we can act upon it
            return RedirectToAction("QuickLogin", input);
        }

        // No windows credentials have been passed at this point
        return View();
    }


    [HttpGet("HasUserWindowsAuth")]
    [Authorize(AuthenticationSchemes = IISDefaults.AuthenticationScheme)]
    public IActionResult HasUserWindowsAuth() => Ok();


    [HttpGet("QuickLogin")]
    [Authorize(AuthenticationSchemes = IISDefaults.AuthenticationScheme)]
    public async Task<IActionResult> QuickLoginAsync(LoginModel input, CancellationToken cancellationToken)
    {
        var user = this.User.Identities.FirstOrDefault(i => i System.Security.Principal.WindowsIdentity && i.IsAuthenticatd);
        // do something with that user
    }

0
投票

我阅读了有关该主题的所有内容,但无法使其发挥作用。当我设置匿名 = true 时,Windows 帐户无法读取并保持为空。这是我使用 IISexpress 运行 Core Web 应用程序时的情况。 当我使用 Challengeasync 时,结果保持不变。

© www.soinside.com 2019 - 2024. All rights reserved.