将 Azure AD B2C 用户连接到我的数据库帐户的正确 Core 3.0 API 中间件?

Posted

技术标签:

【中文标题】将 Azure AD B2C 用户连接到我的数据库帐户的正确 Core 3.0 API 中间件?【英文标题】:Proper Core 3.0 API middleware to connect Azure AD B2C user to my database account? 【发布时间】:2020-02-12 13:17:45 【问题描述】:

我有一个 .Net Core 3 API,可以正确授权和验证通过 Azure AD B2C 传递给它的令牌。它还构建了一些自定义代码,用于检查 JWT 令牌中传递的范围,以确认对端点的访问。 (我正在使用 Microsoft.AspNetCore.Authentication.AzureADB2C.UI 包)这是使这成为可能的中间件块:

services.AddAuthentication(AzureADB2CDefaults.BearerAuthenticationScheme)
                .AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));

var issuer = $"https://Configuration["AzureAdB2C_Custom:TenantB2CHost"]/Configuration["AzureAdB2C:Domain"]/v2.0/";
services.AddAuthorization(options =>
     
          options.AddPolicy("api_read", policy => policy.Requirements.Add(new HasScopeRequirement("api_read", issuer)));
          options.AddPolicy("api_write", policy => policy.Requirements.Add(new HasScopeRequirement("api_write", issuer)));
     );

这一切似乎都在努力正确地访问端点。然后,这些端点在模型中公开我的 SQL 数据库中的各种信息。

但是,现在我正试图通过控制对在这些端点中检索到的数据的特定部分的访问,根据 JWT 令牌在我的数据库中实际与谁相关联,将我的安全性的另一个方面带回家。

在我的特定情况下,我有一个 Accounts 表,我可以在其中存储在 JWT 令牌中找到的来自 Azure AD B2C 的 ObjectID,然后在调用时使用该 ObjectID 获取 Account。我可以在端点的顶部执行此操作,但我怀疑这不是最好的方法。似乎我应该在 Startup 的中间件层构建它作为某种处理程序。

有人可以为我确认这是正确的方法,并可能给我一个例子,或者至少为我指明正确的方向吗?

【问题讨论】:

这可能对joonasw.net/view/adding-custom-claims-aspnet-core-2有帮助 @juunas,非常感谢您的回复。它帮助我非常接近我正在寻找的东西。我最终不得不做一些不同的事情,因为我使用 Azure AD B2C 库来处理身份验证。我将在下面发布我的解决方案以及我发现的一个链接,它可以帮助我完成剩下的工作 - 它与您的链接非常相​​似。 【参考方案1】:

感谢大家的回复。这是我为其他处理此问题的人所做的。向@juunas 大喊他发送的链接,这让我走上了正确的道路。该特定解决方案还不够,因为我使用 Azure AD B2C 库进行授权/身份验证。

这是我找到的链接,一旦我尝试从@juunas 实施解决方案: https://blog.denious.net/azure-b2c-role-based-authorization-part-1/

根据我在该链接中发现的内容,我的解决方案最终看起来像这样:

//Azure ADB2C is injected for authentication
        services.AddAuthentication(AzureADB2CDefaults.BearerAuthenticationScheme)
            .AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));

        services.PostConfigure<JwtBearerOptions>(
            AzureADB2CDefaults.JwtBearerAuthenticationScheme,
            o =>
            
                o.Events = new JwtBearerEvents
                
                    OnTokenValidated = ctx =>
                    
                        //Get user's immutable object id from claims that came from Azure AD
                        string oid = ctx.Principal
                            .FindFirstValue("http://schemas.microsoft.com/identity/claims/objectidentifier");

                        //Get My Data EF context
                        var db = ctx.HttpContext.RequestServices.GetRequiredService<MyDataContext>();

                        //Grab the user - found in My Accounts table, tied to OID
                        var user = db.Accounts.Include("AccountType")
                            .Where(a => a.AuthorityId == oid)
                            .FirstOrDefault();

                        if (user != null)
                        
                            // since we're using AADB2C only, the first identity is the only identity
                            var identity = ctx.Principal.Identities.First();

                            //Place My user type into the claims as a role claim type
                            var extraRoleClaim = new Claim(identity.RoleClaimType, user.AccountType);
                            identity.AddClaim(extraRoleClaim);
                        

                        return Task.CompletedTask;
                    
                ;
            );

设置完成后,我就可以在端点内执行此操作:

if (User.IsInRole("Some Role"))
            
                return Ok();
            
            else
            
                return StatusCode(403, "Forbidden - Unacceptable Role");
            

请注意链接中,我还可以在我的授权属性中对控制器或操作执行以下操作:[Authorize(Roles = "Some Role")]

【讨论】:

非常感谢您的回答。由于 AD B2C 不支持开箱即用的角色,因此我肯定在努力弄清楚如何在不实施完整身份解决方案的情况下执行基于角色的授权。这是一种享受! (特别是 OnTokenValidated) 甜蜜!很高兴这有帮助!【参考方案2】:

基本上,您需要添加一个自定义属性并将其包含在 JWT 中。

如here 中所述 您也可能需要使用graph API 保持属性同步,方法是使用此Sample

【讨论】:

我了解这些属性,这可能对我有所帮助。但最终,我认为我不想开始将有关登录用户的所有内容存储在 Azure AD 用户中。我仍然希望将它们与我的系统联系起来,我认为最好在每次通话时都这样做。所以我仍然认为我想知道执行对我的数据库的调用的最佳方式是什么,使用来自令牌的对象 ID 等信息,并将其作为一种“启动器”信息携带到任何端点调用中。有意义吗? 登录后可以调用一次数据库,将需要的信息存储在Redis缓存中【参考方案3】:

由于缺少 application.json 中的配置,我在示例中遇到了一些困难,而且由于 .net 核心版本之间的变化,谷歌搜索有点混乱。

【讨论】:

很抱歉这么久没有回复 - 我错过了您的消息通知。你还在为此苦苦挣扎吗?您特别需要我的 application.json 文件中的什么来帮助解决这个问题?

以上是关于将 Azure AD B2C 用户连接到我的数据库帐户的正确 Core 3.0 API 中间件?的主要内容,如果未能解决你的问题,请参考以下文章

Azure AD 与 Azure AD B2C 与 Azure AD B2B

Azure AD B2C 错误 - IDX10501:签名验证失败

Azure AD B2C:注销社交帐户(使用 OIDC 的 Azure AD)

Azure AD B2C 将用户流与应用一对一关联

Azure AD B2C 与企业 (Azure?) AD 帐户集成

如何从 Azure B2C 获取 ASPCore 中的 OID 声明