Azure AD B2C 自定义用户属性

min*_*int 4 azure azure-ad-graph-api azure-ad-b2c

我是 Azure B2C 世界的新手。我正在尝试创建一个自定义用户属性来为我们的应用程序存储数据。我已在 Azure 门户中创建它并将其分配给我的注册/登录策略。但是,我希望能够以编程方式更新/读取此值。我一直在走使用 Graph API 和注册扩展的路线。所以两个问题:

1) 扩展/自定义属性是一回事吗?2)我试过这段代码,返回的扩展名总是空的:

 public void RegisterExtension()
    {
        string myRegisteredAppObjectId = "<>";
        string json = @"{
                        ""name"": ""My Custom Attribute"",
                        ""dataType"": ""String"",
                        ""targetObjects"": [
                            ""User""
                        ]
                        }";

        B2CGraphClient b2CGraphClient = new B2CGraphClient();
        b2CGraphClient.RegisterExtension(myRegisteredAppObjectId, json);
        var extensions = JsonConvert.DeserializeObject(b2CGraphClient.GetExtensions(myRegisteredAppObjectId).Result);

    }
Run Code Online (Sandbox Code Playgroud)

B2CGraphClient.cs

 public class B2CGraphClient
{
    private string clientId { get; set; }
    private string clientSecret { get; set; }
    private string tenant { get; set; }

    private AuthenticationContext authContext;
    private ClientCredential credential;

    public B2CGraphClient(string clientId, string clientSecret, string tenant)
    {
        // The client_id, client_secret, and tenant are pulled in from the App.config file
        this.clientId = clientId;
        this.clientSecret = clientSecret;
        this.tenant = tenant;

        // The AuthenticationContext is ADAL's primary class, in which you indicate the direcotry to use.
        this.authContext = new AuthenticationContext("https://login.microsoftonline.com/" + tenant);

        // The ClientCredential is where you pass in your client_id and client_secret, which are 
        // provided to Azure AD in order to receive an access_token using the app's identity.
        this.credential = new ClientCredential(clientId, clientSecret);
    }


    public async Task<string> DeleteUser(string objectId)
    {
        return await SendGraphDeleteRequest("/users/" + objectId);
    }

    public async Task<string> RegisterExtension(string objectId, string body)
    {
        return await SendGraphPostRequest("/applications/" + objectId + "/extensionProperties", body);
    }


    public async Task<string> GetExtensions(string appObjectId)
    {
        return await SendGraphGetRequest("/applications/" + appObjectId + "/extensionProperties", null);
    }


    private async Task<string> SendGraphPostRequest(string api, string json)
    {
        // NOTE: This client uses ADAL v2, not ADAL v4
        AuthenticationResult result = authContext.AcquireToken(Globals.aadGraphResourceId, credential);
        HttpClient http = new HttpClient();
        string url = Globals.aadGraphEndpoint + tenant + api + "?" + Globals.aadGraphVersion;

        Console.ForegroundColor = ConsoleColor.Cyan;
        Console.WriteLine("POST " + url);
        Console.WriteLine("Authorization: Bearer " + result.AccessToken.Substring(0, 80) + "...");
        Console.WriteLine("Content-Type: application/json");
        Console.WriteLine("");
        Console.WriteLine(json);
        Console.WriteLine("");

        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url);
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
        request.Content = new StringContent(json, Encoding.UTF8, "application/json");
        HttpResponseMessage response = await http.SendAsync(request);

        if (!response.IsSuccessStatusCode)
        {
            string error = await response.Content.ReadAsStringAsync();
            object formatted = JsonConvert.DeserializeObject(error);
            throw new WebException("Error Calling the Graph API: \n" + JsonConvert.SerializeObject(formatted, Formatting.Indented));
        }

        Console.ForegroundColor = ConsoleColor.Green;
        Console.WriteLine((int)response.StatusCode + ": " + response.ReasonPhrase);
        Console.WriteLine("");

        return await response.Content.ReadAsStringAsync();
    }

    public async Task<string> SendGraphGetRequest(string api, string query)
    {
        // First, use ADAL to acquire a token using the app's identity (the credential)
        // The first parameter is the resource we want an access_token for; in this case, the Graph API.
        AuthenticationResult result = authContext.AcquireToken("https://graph.windows.net", credential);

        // For B2C user managment, be sure to use the 1.6 Graph API version.
        HttpClient http = new HttpClient();
        string url = "https://graph.windows.net/" + tenant + api + "?" + Globals.aadGraphVersion;
        if (!string.IsNullOrEmpty(query))
        {
            url += "&" + query;
        } 

        Console.ForegroundColor = ConsoleColor.Cyan;
        Console.WriteLine("GET " + url);
        Console.WriteLine("Authorization: Bearer " + result.AccessToken.Substring(0, 80) + "...");
        Console.WriteLine("");

        // Append the access token for the Graph API to the Authorization header of the request, using the Bearer scheme.
        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
        HttpResponseMessage response = await http.SendAsync(request);

        if (!response.IsSuccessStatusCode)
        {
            string error = await response.Content.ReadAsStringAsync();
            object formatted = JsonConvert.DeserializeObject(error);
            throw new WebException("Error Calling the Graph API: \n" + JsonConvert.SerializeObject(formatted, Formatting.Indented));
        }

        Console.ForegroundColor = ConsoleColor.Green;
        Console.WriteLine((int)response.StatusCode + ": " + response.ReasonPhrase);
        Console.WriteLine("");

        return await response.Content.ReadAsStringAsync();
    } 
}
Run Code Online (Sandbox Code Playgroud)

当然,里面myRegisteredAppObjectId有一个有效的 GUID。

谢谢

Tom*_*SFT 5

扩展/自定义属性是一回事吗?

根据我的测试,扩展与自定义属性是一回事。

我试过这段代码,返回的扩展名总是空的:

MyCustomAttribute按照本教程添加自定义属性,在我的策略中使用自定义属性。你可以参考我的测试步骤。

我从 Github下载了B2C-GraphAPI-DotNet项目。对自定义属性使用以下代码

var applications = client.GetApplications("$filter=startswith(displayName, 'b2c-extensions-app')").Result

var extension = client.GetExtensions(objectId).Result //objectId from the applications result.
Run Code Online (Sandbox Code Playgroud)

然后我们可以从扩展中获取自定义属性。

在此处输入图片说明

然后,您可以像对待用户对象上的任何其他属性一样对待该属性

比如创建一个用户:

var jsonObject = new JObject
            {
                {"accountEnabled", true},
                {"country", "US"},
                {"creationType", "LocalAccount"},
                {"displayName", "Tomsun"},
                {"passwordPolicies", "DisablePasswordExpiration,DisableStrongPassword"},
                { "extension_42ba0de8530a4b5bbe6dad21fe6ef092_MyCustomAttribute","test2"},  //custom propery
                {"passwordProfile", new JObject
                {
                    {"password", "!QAZ1234wer"},
                    {"forceChangePasswordNextLogin", true}
                } },
                {"signInNames", new JArray
                    {
                        new JObject
                        {
                            {"value","tom1@example.com"},
                            {"type", "emailAddress"}
                        }
                    }
                }
            };

string user = client.CreateUser(jsonObject.ToString()).Result;
Run Code Online (Sandbox Code Playgroud)

查询用户

var user = client.GetUserByObjectId(objectId).Result; //user objectId
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

更新用户

var jsonUpdate = new JObject
            {  
                { "extension_42ba0de8530a4b5bbe6dad21fe6ef092_MyCustomAttribute","testx"}

            };
var updateuser = client.UpdateUser("objectId", jsonObject2.ToString()).Result; //UserObject Id
Run Code Online (Sandbox Code Playgroud)