在 Asp.Net Core Web 应用程序中使用 EasyAuth 对 Azure 应用服务上的 AAD 进行身份验证时,无法填充 ClaimsPrincipal

Posted

技术标签:

【中文标题】在 Asp.Net Core Web 应用程序中使用 EasyAuth 对 Azure 应用服务上的 AAD 进行身份验证时,无法填充 ClaimsPrincipal【英文标题】:Trouble getting ClaimsPrincipal populated when using EasyAuth to authenticate against AAD on Azure App Service in a Asp.Net Core web app 【发布时间】:2017-05-20 23:23:49 【问题描述】:

我们有一个基于 Asp.Net 核心的网络应用程序。它不包含任何配置的身份验证中间件。

我们托管在 Azure 应用服务上,并使用身份验证/授权选项 (EasyAuth) 对 Azure AD 进行身份验证。

身份验证运行良好 - 我们插入了必要的标头,我们可以在 /.auth/me 中看到经过身份验证的身份。但是 HttpContext.User 属性没有被填充。

这是 Asp.Net 核心的兼容性问题吗?还是我做错了什么?

【问题讨论】:

@chris-gillum - 如果你能提供帮助,那就太好了...... 【参考方案1】:

我创建了一个自定义中间件,用于填充用户属性,直到 Azure 团队解决此问题。

它从应用服务身份验证中读取标头并创建一个用户,该用户将被[Authorize] 识别并拥有name 的声明。

// Azure app service will send the x-ms-client-principal-id when authenticated
app.Use(async (context, next) =>


    // 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(azureAppServicePrincipalIdHeader);
        identity.AddClaims(claims);

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

    await next.Invoke();
);

【讨论】:

@ChrisGillum 非常感谢这篇文章,它帮助了我。我有一个后续问题。我在后端使用 ASP Membership 进行授权。将用户添加到 Context 似乎并没有让他们登录。有没有办法可以从同一段代码调用 SignInManager 来做到这一点?【参考方案2】:

是的,这是一个兼容性问题。不幸的是,ASP.NET Core 不支持将身份信息从 IIS 模块(如 Easy Auth)流向应用程序代码。这意味着 HttpContext.User 和类似的代码不会像普通的 ASP.NET 那样工作。

目前的解决方法是从您的服务器代码调用您的网络应用程序的 /.auth/me 端点来获取用户声明。然后,您可以使用 x-ms-client-principal-id 请求标头值作为缓存键来适当地缓存此数据。 /.auth/me 调用需要进行正确的身份验证,就像对 Web 应用程序的调用需要进行身份验证一样(身份验证 cookie 或请求标头令牌)。

【讨论】:

谢谢你,克里斯。我们还需要根据我们从 AAD 获得的身份从应用程序数据库中添加额外的声明。所以,我想我会考虑添加一个自定义中间件的选项,该中间件通过 .auth/me 和数据库一起读取信息,并从那里创建 ClaimsPrincipal。它将允许我们保留 Asp.Net Core 身份验证/授权框架的其余部分。 现在已经快 2 年了,azure/Microsoft 仍未更新 azure web[/api/mobile] 应用程序 EasyAuth 实现更新,该更新自动处理将 EasyAuth 身份验证用户 X-MS-* 标头数据映射到this.User 对象是否类似于您在 asp.net 核心 Web 应用程序中自己实现 oauth 或 openid 连接身份验证代码时显示的位置?我刚刚完成了对 azure function app v2 的测试,他们的 EasyAuth 故事为您完成了这项工作,并允许您将 ClaimsPrincipal 依赖注入到您想要的任何函数 [/控制器方法] 中。 @myusrn ASP.NET Core 的设计不允许自动注入。不幸的是,这需要在应用代码中完成。 很公平,但是包含一个 nuget 包,它的工作方式类似于某些人已经破解的工作,这难道不是有意义的吗? 嗨@Chris Gilliam,我不应该期望easyauth过滤器总是采用浏览器客户端openid连接或本机应用程序oauth授权标头承载令牌身份验证,并从中创建X-MS-CLIENT-PRINCIPAL -NAME、X-MS-CLIENT-PRINCIPAL-IDP、X-MS-CLIENT-PRINCIPAL、X-MS-TOKEN-AAD-ID-TOKEN 等我可以信任并用于创建 this.Context.User 的请求标头导致 azurewebsites.net/.auth/me 不需要网络请求?【参考方案3】:

为此,我编写了一个小的基本中间件。它将基于 .auth/me 端点创建一个身份。身份在身份验证管道中创建,以便 [授权] 属性和策略与身份一起使用。

你可以在这里找到它:

https://github.com/lpunderscore/azureappservice-authentication-middleware

或在 nuget 上:

https://www.nuget.org/packages/AzureAppserviceAuthenticationMiddleware/

添加后,只需将此行添加到您的启动:

app.UseAzureAppServiceAuthentication();

【讨论】:

我查看了 Repo 并尝试了它但没有成功。在我看来,您似乎没有将诸如 X-ZUMO-AUTH 之类的标头传递给 /.auth/me。您正在发送 cookie。这可能是问题吗? GitHub 存储库已更新为也可以使用标头。我在我的应用中成功使用了它 @n00b 感谢您的贡献,您的更改已合并,我会尽快更新 nuget。 嗨,我做了一些工作以使其与 asp.net core 2.0 及更高版本一起使用。我会很感激这里的一些反馈:github.com/kirkone/KK.AspNetCore.EasyAuthAuthentication @KirKone 感谢更新,因为我正在尝试使用 asp.net core 2.1+ Web 应用程序项目来做所有事情,以便在 azure 函数应用程序、Web 应用程序和容器部署方案中具有一定的可移植性。我尝试了 user3159405 nuget,它在运行时爆炸了。我尝试了您的解决方案,它在运行时没有崩溃,但我遇到的问题是它适用于 easyauth 浏览器 openid 连接会话 cookie 请求,但不适用于 easyauth 桌面/移动应用程序 oauth 授权标头承载令牌安全请求。将问题发布到您的 GitHub 存储库,以尝试合作解决问题。【参考方案4】:

以下代码从 Azure 应用服务 HTTP 标头解密 AAD 令牌,并使用声明填充 HttpContext.User。这很粗糙,因为您希望缓存配置而不是在每个请求中查找它:

    OpenIdConnectConfigurationRetriever r = new OpenIdConnectConfigurationRetriever();
    ConfigurationManager<OpenIdConnectConfiguration> configManager = new ConfigurationManager<OpenIdConnectConfiguration>(options.Endpoint, r);
    OpenIdConnectConfiguration config = await configManager.GetConfigurationAsync();

    var tokenValidationParameters = new TokenValidationParameters
    
        ValidateIssuerSigningKey = true,
        IssuerSigningKeys = config.SigningKeys.ToList(),
        ValidateIssuer = true,
        ValidIssuer = config.Issuer,
        ValidateAudience = true,
        ValidAudience = options.Audience,
        ValidateLifetime = true,
        ClockSkew = new TimeSpan(0, 0, 10)
    ;

    JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();

    ClaimsPrincipal principal = null;
    SecurityToken validToken = null;

    string token = context.Request.Headers["X-MS-TOKEN-AAD-ID-TOKEN"];

    if (!String.IsNullOrWhiteSpace(token))
    
        principal = handler.ValidateToken(token, tokenValidationParameters, out validToken);

        var validJwt = validToken as JwtSecurityToken;

        if (validJwt == null)  throw new ArgumentException("Invalid JWT"); 

        if (principal != null)
        
            context.User.AddIdentities(principal.Identities);
        
    

它仅适用于 Azure AD。要支持其他 ID 提供者(Facebook、Twitter 等),您必须检测相关标头并弄清楚如何解析每个提供者的令牌。但是,它应该只是上述主题的变体。

【讨论】:

只需要解析JWT。 Azure 应用服务已经对其进行了验证。这将大大简化您的解决方案。【参考方案5】:

你可以试试这个库。我遇到了类似的问题并创建了这个以简化使用。

https://github.com/dasiths/NEasyAuthMiddleware

用于 ASP.NET 的 Azure 应用服务身份验证 (EasyAuth) 中间件 CORE 具有完全可定制的组件,支持本地 调试

它通过注册自定义身份验证处理程序来补充 HttpContext.User。为了在本地运行时更轻松,它甚至可以使用 json 文件来加载模拟声明。

【讨论】:

以上是关于在 Asp.Net Core Web 应用程序中使用 EasyAuth 对 Azure 应用服务上的 AAD 进行身份验证时,无法填充 ClaimsPrincipal的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Core Web 应用程序系列- 在ASP.NET Core中使用AutoMapper进行实体映射

ASP.NET Core 入门教程 1使用ASP.NET Core 构建第一个Web应用

ASP.NET Core 入门教程 1使用ASP.NET Core 构建第一个Web应用

ASP.NET Core Web 应用程序系列- 在ASP.NET Core中使用Autofac替换自带DI进行批量依赖注入(MVC当中应用)

如何在 ASP.NET (Core 2) Web 应用程序中访问来自 AWS 的认证?

net core体系-web应用程序7asp.net core日志组件