.Net 6:为一个启用 Windows 和匿名身份验证

.Net 6: Enable Windows and Anonymous authentication for one

我在 .Net 核心应用程序上工作,我需要在同一个端点内混合使用 windows 和匿名身份验证。所以目标是能够确定 windows 用户,但是当没有 windows 用户存在时端点也应该工作(又名 windows 身份验证失败)。

我的问题是,当我使用授权属性时(如下例所示),只有在 windows 身份验证成功时才会调用端点。如果我另外添加 [AllowAnonymous] 属性,则用户永远不会通过身份验证。

示例:(

[Authorize(AuthenticationSchemes = IISDefaults.AuthenticationScheme)]
public IActionResult Index()
{
    _log.LogDebug("IsAuthenticated = " + this.User.Identity.IsAuthenticated.ToString());
    _log.LogDebug("Authenticated Name: " + this.User.Identity.IsAuthenticated.Name);

    return View();
}

如何在 .Net 6.0 中完成此操作?它应该非常简单,因为身份验证和授权应该分开,但看起来它们是交织在一起的。经过广泛的谷歌搜索、检查 .net 核心源代码并亲自尝试后,我还没有找到解决方案。 有什么好的方法可以解决吗?

备注 1:有适用于 .Net core 3.1 的解决方案,但不适用于 .Net 6

备注 2:我们的端点必须使用 Windows 身份验证,而其他端点必须使用匿名身份验证。这些都在同一个应用程序中工作良好。这实际上是关于能够在支持任意身份验证的端点中检测到 windows 用户。

我(或者更好的是我们)找到了一种解决方案,即使在 IIS 上禁用 Windows 身份验证时也能正常工作。它不是很优雅,但这是我们想出的。这个想法基本上是触发对端点的另一个调用以确定用户是否实际上是 windows 登录。如果此调用成功,则我们知道我们有一个 windows 用户并可以采取相应行动,例如重定向到需要 windows 身份验证的端点。

备注:如果您可以控制 IIS 设置(这可能是经常发生的情况),那么我建议您使用此处提出的解决方案: )

    [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
    }