.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
相关产品推荐
相关产品推荐

