web-dev-qa-db-ja.com

Azure B2C:JWTトークンで「グループ」クレームを取得するにはどうすればよいですか

Azure B2Cでは、次のようにしてJWTトークンで「グループ」クレームを取得できました JWTを使用してAzure ADグループ情報を取得する

  • 昔ながらのAzureマネージャーを開きます( https://manage.windowsazure.com
  • アプリケーションをB2Cに登録する
  • アプリケーションのB2Cマニフェストをダウンロードします
  • マニフェストで、「groupMembershipClaims」エントリを[.____]に変更します。

    "groupMembershipClaims": "SecurityGroup"、

  • 変更したB2Cマニフェストを再度アップロードする

問題

これは過去にうまく機能していましたが(約1か月前、私は信じています...)、現在は機能していません。詳細は以下をご覧ください...

私がソファを試したこと

プランA:AzureManagerを使用する

上記の既知のレシピに従ってください。

残念ながら、それはもう機能しません-このクライアントがB2Cで私を認証しようとすると、次のエラーが発生します。

AADB2C90068:ID '032fe196-e17d-4287-9cfd-25386d49c0d5'で提供されたアプリケーションは、このサービスに対して無効です。 B2Cポータルで作成したアプリケーションを使用して、もう一度お試しください。」

OK、十分に公平です-彼らは私たちを新しいポータルに移動させています。

プランB:Azureポータルを使用する

新しいポータルを使用して、古き良きレシピに従ってください。

しかし、それも機能しません。「マニフェストのダウンロード」の部分に到達すると、マニフェストにアクセスする方法が見つかりません(そして、グーグルは、おそらく永久になくなったと言っています...)。

プランC:Azureポータルとマネージャーを組み合わせる

少し必死になって、プランAとプランBを組み合わせてみました。新しいポータルを使用してアプリを登録し、古いAzureManagerを使用してマニフェストを変更します。

しかし運が悪い-マニフェストをアップロードしようとすると、メッセージで失敗します

ParameterValidationException =提供された無効なパラメーター。 BadRequestException =このバージョンではコンバージドアプリケーションへの更新は許可されていません。

Plan Z:GraphAPIを使用してグループメンバーシップデータを取得する

「グループ」の主張をあきらめるだけです。代わりに、グループ情報が必要なときはいつでも、GraphAPIを使用してB2Cサーバーにクエリを実行するだけです。

私は本当に、本当にこれをしたくありません-それはアクセストークンの自己完結性を台無しにし、システムを非常に「おしゃべり」にします。

しかし、私はそれをプランZとしてここに含めました:はい、私はオプションが存在することを知っています、いいえ私はそれを試していません-そして私はしたくないです。

質問:

最近、JWTトークンで「グループ」クレームを取得するにはどうすればよいですか?

17

計画Zそれは私が恐れていることです。なぜ返品されないのかわかりませんが、現在は フィードバックポータルで計画どおりにマークされています(最も評価の高いアイテムです)

これが私のやり方です。ユーザーが認証されたときにグループにクエリを実行することもできます。必要に応じてクエリを実行するだけです。ユースケースによって異なります。

public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
        app.UseKentorOwinCookieSaver();
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            LoginPath = new PathString("/account/unauthorised"),
            CookieSecure = CookieSecureOption.Always,
            ExpireTimeSpan = TimeSpan.FromMinutes(20),
            SlidingExpiration = true,
            CookieHttpOnly = true
        });

        // Configure OpenID Connect middleware for each policy
        app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(Globals.SignInPolicyId));
    }

    private OpenIdConnectAuthenticationOptions CreateOptionsFromPolicy(string policy)
    {
        return new OpenIdConnectAuthenticationOptions
        {
            // For each policy, give OWIN the policy-specific metadata address, and
            // set the authentication type to the id of the policy
            MetadataAddress = string.Format(Globals.AadInstance, Globals.TenantName, policy),
            AuthenticationType = policy,
            AuthenticationMode = AuthenticationMode.Active,
            // These are standard OpenID Connect parameters, with values pulled from web.config
            ClientId = Globals.ClientIdForLogin,
            RedirectUri = Globals.RedirectUri,
            PostLogoutRedirectUri = Globals.RedirectUri,
            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                AuthenticationFailed = AuthenticationFailed,
                SecurityTokenValidated = SecurityTokenValidated
            },
            Scope = "openid",
            ResponseType = "id_token",

            // This piece is optional - it is used for displaying the user's name in the navigation bar.
            TokenValidationParameters = new TokenValidationParameters
            {
                NameClaimType = "name",
            }
        };
    }

    private async Task SecurityTokenValidated(SecurityTokenValidatedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> token)
    {
            var groups = await _metaDataService.GetGroups(token.AuthenticationTicket.Identity.FindFirst("http://schemas.Microsoft.com/identity/claims/objectidentifier").Value);

            if (groups?.Value != null && groups.Value.Any())
            {
                foreach (IGroup group in groups.Value.ToList())
                {
                    token.AuthenticationTicket.Identity.AddClaim(
                        new Claim(ClaimTypes.Role, group.DisplayName, ClaimValueTypes.String, "GRAPH"));
                }
            }
    }

    // Used for avoiding yellow-screen-of-death
    private Task AuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
    {
        notification.HandleResponse();

        if (notification.Exception.Message == "access_denied")
        {
            notification.Response.Redirect("/");
        }
        else
        {
            notification.Response.Redirect("/error?message=" + notification.Exception.Message);
        }

        return Task.FromResult(0);
    }
}

私のGetGroupsメソッドは、ユーザーAPIの getMemberGroupsメソッド をクエリするだけです。

次に、ユーザーがロールに属しているかどうかを判断するための簡単なヘルパーメソッドがあります。

public static bool UserIsInRole(IPrincipal user, string roleName)
{
    var claims = user.Identity as ClaimsIdentity;

    if (claims == null) return false;

    return claims.FindAll(x => x.Type == ClaimTypes.Role).Any(x => x.Value == roleName);
}
7
gfyans