You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 8 WebAPI调用Microsoft Graph API无法获取Entra ID用户自定义安全属性

问题:.NET 8 WebAPI无法获取Entra ID自定义安全属性的具体键值对

我开发了一个.NET 8 WebAPI用于拉取Entra ID用户详情,其他属性均可正常获取,但customSecurityAttributes仅能拉取到属性集名称(如devDetails),无法获取具体的自定义属性名称和值,返回空对象。Node.js版本可正常获取完整属性值,请求协助解决。


.NET 8 WebAPI代码

接口方法

[HttpGet("specificcust/{UUID}")]
public async Task<IActionResult> GetUserDetailsCust(string UUID)
{
    var result = await _graphClient.Users[UUID].GetAsync(requestConfiguration =>
        {
            requestConfiguration.QueryParameters.Select = new string[] { "customSecurityAttributes" };
        });

        if (result.CustomSecurityAttributes != null && result.CustomSecurityAttributes.AdditionalData != null)
        {
            foreach (var attribute in result.CustomSecurityAttributes.AdditionalData)
            {
                var json = JsonSerializer.Serialize(attribute.Value);
                Console.WriteLine($"{attribute.Key}: {json}");
                return Ok(json);
            }
        }
        else
        {
            Console.WriteLine("No custom security attributes found.");
        }
    return Ok(result.ToString());
}

Graph服务客户端实现

public class GraphApiService
{
    private readonly IConfiguration _configuration;
    private readonly GraphServiceClient _graphClient;
    public GraphServiceClient GraphClient => _graphClient;

public GraphApiService(IConfiguration configuration)
{
    _configuration = configuration;
    _graphClient = GetGraphServiceClient();
}

private GraphServiceClient GetGraphServiceClient()
{
    var clientSecretCredential = new ClientSecretCredential(
        _configuration["AzureAd:TenantId"],
        _configuration["AzureAd:ClientId"],
        _configuration["AzureAd:ClientSecret"]
    );

    return new GraphServiceClient(clientSecretCredential, 
    new[] { "https://graph.microsoft.com/.default" });
}
}

.NET代码输出结果

devDetails: {}


可正常工作的Node.js(Express JS)代码

const express = require("express");
const app = express();

const { Client } = require("@microsoft/microsoft-graph-client");
const { ClientSecretCredential } = require("@azure/identity");
CUS_PORT = 3500;
const fetch = require("node-fetch");

if (!globalThis.fetch) {
  globalThis.fetch = fetch;
}

app.use(express.json({ limit: "5mb" }));
app.use(express.urlencoded({ extended: false }));

const tenantId = "";
const clientId = "";
const clientSecret = "";
const UUID = "";

const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);

const client = Client.init({
  authProvider: async (done) => {
    try {
      const accessToken = await credential.getToken(
        "https://graph.microsoft.com/.default"
      );
      done(null, accessToken.token);
    } catch (error) {
      done(error, null);
    }
  },
});

app.get("/getData", async (req, res) => {
  try {
    // const UUID = req.params.UUID;
    const result = await client
      .api(`/users/${UUID}`)
      .select("customSecurityAttributes")
      .get();

    res.status(200).send(result);
  } catch (error) {
    console.error(error);
    res.status(500).send(error);
  }
});

app.listen(CUS_PORT, () => {
  console.log(
    `API is running on ${CUS_PORT} port started at ${new Date().toDateString()} ${new Date().toLocaleTimeString()}`
  );
});

Node.js代码输出结果

{
  "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users(customSecurityAttributes)/$entity",
  "customSecurityAttributes": {
    "devDetails": {
      "@odata.type": "#microsoft.graph.customSecurityAttributeValue",
      "devLocation": "Canada",
      "devOrAdmin": 1,
      "devLab": "BIRG"
    }
  }
}

解决方案

问题源于Microsoft Graph .NET SDK的默认对象映射逻辑,customSecurityAttributes的嵌套属性不会自动解析到AdditionalData中,可通过以下方式解决:

方案1:直接获取原始响应并解析

绕开SDK的对象映射,直接获取API返回的原始JSON内容:

[HttpGet("specificcust/{UUID}")]
public async Task<IActionResult> GetUserDetailsCust(string UUID)
{
    // 构建请求信息
    var requestInfo = _graphClient.Users[UUID].ToGetRequestInformation(requestConfiguration =>
    {
        requestConfiguration.QueryParameters.Select = new string[] { "customSecurityAttributes" };
    });

    // 发送请求并获取原始JSON响应
    var response = await _graphClient.RequestAdapter.SendAsync(requestInfo, typeof(JsonElement), cancellationToken: HttpContext.RequestAborted);
    
    if (response.TryGetProperty("customSecurityAttributes", out var custAttrs))
    {
        return Ok(custAttrs.ToString());
    }
    
    return Ok("No custom security attributes found.");
}

方案2:配置SDK序列化选项

修改GraphServiceClient的创建逻辑,配置JSON序列化规则以保留所有附加数据:

private GraphServiceClient GetGraphServiceClient()
{
    var clientSecretCredential = new ClientSecretCredential(
        _configuration["AzureAd:TenantId"],
        _configuration["AzureAd:ClientId"],
        _configuration["AzureAd:ClientSecret"]
    );

    // 配置序列化选项
    var jsonSerializerOptions = new JsonSerializerOptions
    {
        PropertyNameCaseInsensitive = true,
        WriteIndented = true,
        Converters = { new JsonStringEnumConverter() }
    };

    var adapter = new HttpClientAdapter(clientSecretCredential, new[] { "https://graph.microsoft.com/.default" })
    {
        JsonSerializerOptions = jsonSerializerOptions
    };

    return new GraphServiceClient(adapter);
}

同时调整接口方法中的序列化逻辑:

var json = JsonSerializer.Serialize(result.CustomSecurityAttributes, jsonSerializerOptions);
return Ok(json);

方案3:显式展开已知属性集

若提前知晓属性集名称,可在select中指定展开该属性集(仅适用于已知属性集的场景):

var result = await _graphClient.Users[UUID].GetAsync(requestConfiguration =>
{
    requestConfiguration.QueryParameters.Select = new string[] { "customSecurityAttributes/devDetails" };
});

内容的提问来源于stack exchange,提问作者Saurabh Kulkarni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 22:44:50