Azure AD B2C - Local IDP with “Username” not provi

2019-04-29 08:57发布

问题:

I've configured an identity provider to use local accounts with usernames rather than passwords.

I have created a user with a Display Name, User Name, and Email.

I am able to select "Display Name" and "Email Address" application claims for all policies, but "User Name" is not an option. I have also confirmed that a username claim is not being provided to my application.

How can I configure Azure AD B2C such that it provides the username claim?

回答1:

Unfortunately, the username isn't available yet for selection as a claim to pass down in the token. You should vote for this ask in the Azure AD B2C UserVoice forum to help prioritize it: Include username in JWT claims

Your only option as this time is to retrieve it yourself via the Graph.

Here's a quick & dirty snippet of .Net code that you can use for this:

    private async Task OnSecurityTokenValidated(SecurityTokenValidatedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
    {
        try
        {
            var userObjectId = notification.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier")?.Value;

            // You'll need to register a separate app for this.
            // This app will need APPLICATION (not Delegated) Directory.Read permissions
            // Check out this link for more info:
            // https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-devquickstarts-graph-dotnet 
            var authContext = new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(string.Format(graphAuthority, tenant));
            var t = await authContext.AcquireTokenAsync(graphResource, new ClientCredential(graphClientId, graphClientSecret));

            string result;
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Add("Authorization", "Bearer " + t.AccessToken);

                var url = graphResource + tenant + "/users/" + userObjectId + "/?api-version=1.6";
                result = await client.GetStringAsync(url);
            }

            var jsonResult = JObject.Parse(result);
            var username = jsonResult["signInNames"].FirstOrDefault(j => j["type"].ToString() == "userName")?["value"]?.ToString();
            notification.AuthenticationTicket.Identity.AddClaim(new Claim("username", username));
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }

You'll reference this method when you setup your OpenIdConnectAuthenticationOptions like so:

    new OpenIdConnectAuthenticationOptions
        {
            // (...)
            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                AuthenticationFailed = OnAuthenticationFailed,
                SecurityTokenValidated = OnSecurityTokenValidated,
            },
            // (...)
        };