User.Identity 不再在启用身份验证的 Azure Web 应用程序中设置

User.Identity no longer set in Azure web app with Authentication enabled

我正在将 .NET 4.8 应用程序迁移到 .NET Core。当前应用运行在Azure上,使用微软作为身份提供者进行身份验证(在Azure应用的Authentication页面设置,代码中没有任何内容,见下图),以便Azure AD中的任何用户都可以访问它。身份验证工作正常,当您尚未使用 Azure AD 帐户登录时,您将重定向到 login.microsoftonline.com 页面。

该应用程序包含一段在 .NET 4.8 中始终有效的简单代码

@if (Request.IsAuthenticated)
{
    <strong>@User.Identity.Name</strong>
}
else
{
    <div><i>Not logged in</i></div>
}

(开发者也可以在本地使用此应用,无需身份验证)

我现在已准备好在 Azure 上测试新应用程序,但我发现 User.Identity 未填充,我连接了一个远程调试器并发现所有属性都是空的(没有声明,默认的标识值)。 我发现了一些主题也报告了这个问题,但其中大多数已经在使用一些代码。 我想我可能遗漏了一些启动代码,但我无法弄清楚它是什么。目前我有

// ConfigureServices
services.AddAuthentication();
services.Configure<IdentityOptions>(options => 
            options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier); // found this somewhere as solution, but didn't work so it's probably not required

// Configure
app.UseAuthentication();
app.UseAuthorization();

总结一下:

经过更多的挖掘,我发现 有同样的问题。所以事实证明它是由 ASP.NET 以不同方式工作的内核引起的。 其中一个答案包含一段解决问题的代码,我用它来创建一个新的简单中间件:

public static class AzureAuthExtensions
{
    /// <summary>
    /// Enables support for Azure EasyAuth, so that User.Identity.Name is populated correctly.
    /// </summary>
    public static IApplicationBuilder UseAzureEasyAuth(this IApplicationBuilder app)
    {
        if (app == null)
        {
            throw new ArgumentNullException(nameof(app));
        }

        return app.UseMiddleware<AzureEasyAuthMiddleware>();
    }
}

public class AzureEasyAuthMiddleware
{
    private readonly RequestDelegate _next;

    public AzureEasyAuthMiddleware(RequestDelegate next)
    {
        _next = next ?? throw new ArgumentNullException(nameof(next));
    }

    /// <summary>
    /// Invoke the middleware.
    /// </summary>
    /// <param name="context">The <see cref="HttpContext"/>.</param>        
    public Task Invoke(HttpContext context)
    {
        // Create a user on current thread from provided header
        if (context.Request.Headers.ContainsKey("X-MS-CLIENT-PRINCIPAL-ID"))
        {
            // Read headers from Azure
            var azureAppServicePrincipalIdHeader = context.Request.Headers["X-MS-CLIENT-PRINCIPAL-ID"][0];
            var azureAppServicePrincipalNameHeader = context.Request.Headers["X-MS-CLIENT-PRINCIPAL-NAME"][0];

            // Create claims id
            var claims = new Claim[] {
                new System.Security.Claims.Claim("http://schemas.microsoft.com/identity/claims/objectidentifier", azureAppServicePrincipalIdHeader),
                new System.Security.Claims.Claim("name", azureAppServicePrincipalNameHeader)
            };

            // Set user in current context as claims principal
            var identity = new GenericIdentity(azureAppServicePrincipalNameHeader);
            identity.AddClaims(claims);

            // Set current thread user to identity
            context.User = new GenericPrincipal(identity, null);
        };

        return _next(context);
    }
}

这很有魅力!