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

使用C#调用Microsoft Graph API执行条件访问策略评估时遭遇BadRequest错误的求助

C#调用Microsoft Graph API执行条件访问策略评估时遭遇BadRequest错误的求助

我正在尝试用C#结合Microsoft Graph API和Microsoft.Graph NuGet包执行条件访问策略评估(Conditional Access Evaluation)(注意:不是创建或更新策略),但所有请求都返回HTTP 400 BadRequest错误。其他Graph请求(比如获取条件访问策略列表)能正常工作,说明认证没有问题。

代码实现

条件访问评估方法

public async Task<CumulativePolicySettings> RunConditionalAccessWhatIfAsync(string _userId, List<string> _includedApplications)
{
    try
    {
        Logger.Information($"Starting Conditional Access What-If check for user {_userId}", _userId);
        using var httpClient = await AzureHttpAuthenticationService.GetAuthenticatedHttpClientAsync();

        var requestBody = new
        {
            signInIdentity = new { userId = _userId },
            signInContext = new { includeApplications = _includedApplications },
            appliedPoliciesOnly = true
        };
        Logger.Information("request body: " + JsonConvert.SerializeObject(requestBody));

        var requestUrl = "https://graph.microsoft.com/beta/identity/conditionalAccess/evaluate";
        var requestContent = new StringContent(JsonConvert.SerializeObject(requestBody), Encoding.UTF8, "application/json");

        var response = await httpClient.PostAsync(requestUrl, requestContent);
        Logger.Information($"HTTP Status Code: {response.StatusCode}");
        Logger.Information($"Response Headers: {response.Headers}");
        
        response.EnsureSuccessStatusCode(); // 此处会因400抛出异常,无法获取详细错误内容

        var responseContent = await response.Content.ReadAsStringAsync();
        Logger.Information(responseContent);

        var policies = JsonConvert.DeserializeObject<List<ConditionalAccessPolicyResult>>(responseContent);
        var cumulativeSettings = new CumulativePolicySettings();
        foreach (var policy in policies)
        {
            cumulativeSettings.AllAppliedControls.AddRange(policy.AppliedControls);
            foreach (var setting in policy.Settings)
            {
                cumulativeSettings.CombinedSettings[setting.Key] = setting.Value;
            }
        }

        Logger.Information("Conditional Access What-If check completed. Policies evaluated: {Count}", policies.Count);
        return cumulativeSettings;
    }
    catch (Exception ex)
    {
        Logger.Error("Error occurred during Conditional Access What-If check: {Message}", ex.Message);
        return null;
    }
}

认证服务实现

private async Task<string> GetAccessTokenAsync()
{
    var app = ConfidentialClientApplicationBuilder.Create(ClientID)
        .WithClientSecret(ClientSecret)
        .WithAuthority(Authority)
        .Build();
    string[] Scopes = { "https://graph.microsoft.com/.default" };
    var result = await app.AcquireTokenForClient(Scopes).ExecuteAsync();
    return result.AccessToken;
}

public async Task<HttpClient> GetAuthenticatedHttpClientAsync()
{
    var httpClient = new HttpClient();
    var token = await GetAccessTokenAsync();
    httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
    return httpClient;
}

当前请求详情

生成的JSON请求体如下:

{
    "signInIdentity":{
        "userId":"123c123d-1a88-44a5-93a6-1230d12365b2"
    },
    "signInContext":{
        "includeApplications":["00000003-0000-0ff1-ce00-000000000000"]
    },
    "appliedPoliciesOnly":true
}

请求返回的日志信息:

2025-06-04 23:15:42.955 +02:00 [INF] HTTP Status Code: BadRequest
2025-06-04 23:15:42.956 +02:00 [INF] Response Headers: Cache-Control: no-cache Transfer-Encoding: chunked Strict-Transport-Security: max-age=31536000 request-id: b30a0e35-0b3c-4274-ae93-977d95ff46dc client-request-id: b30a0e35-0b3c-4274-ae93-977d95ff46dc x-ms-ags-diagnostic: {"ServerInfo":{"DataCenter":"Germany West Central","Slice":"E","Ring":"4","ScaleUnit":"002","RoleInstance":"FR3PEPF00000351"}} Link: [省略] Deprecation: Thu, 17 Feb 2022 23:59:59 GMT Sunset: Sat, 17 Feb 2024 23:59:59 GMT Date: Wed, 04 Jun 2025 21:15:42 GMT

排查与解决方案

1. 先获取Graph返回的详细错误信息

当前代码在response.EnsureSuccessStatusCode()处会直接抛出异常,导致无法获取Graph返回的具体错误描述(比如哪个字段缺失或格式错误)。建议先读取响应内容再判断请求是否成功:

修改代码中的响应处理部分:

var response = await httpClient.PostAsync(requestUrl, requestContent);
Logger.Information($"HTTP Status Code: {response.StatusCode}");
Logger.Information($"Response Headers: {response.Headers}");

// 先读取响应内容,无论状态码是否成功
var responseContent = await response.Content.ReadAsStringAsync();
Logger.Information("Response content: " + responseContent);

if (!response.IsSuccessStatusCode)
{
    Logger.Error("Request failed with content: " + responseContent);
    // 可以根据错误内容做针对性处理
    return null;
}

// 后续正常处理逻辑
var policies = JsonConvert.DeserializeObject<List<ConditionalAccessPolicyResult>>(responseContent);
// ...

Graph通常会返回类似如下的错误信息,帮助定位问题:

{
    "error": {
        "code": "BadRequest",
        "message": "The request body is missing required properties: signInContext.ipAddress",
        "innerError": {
            "date": "2025-06-04T21:15:42",
            "request-id": "b30a0e35-0b3c-4274-ae93-977d95ff46dc",
            "client-request-id": "b30a0e35-0b3c-4274-ae93-977d95ff46dc"
        }
    }
}

2. 确保请求体符合Graph API的格式要求

根据Microsoft Graph官方文档,evaluate端点的请求体需要符合conditionalAccessEvaluationRequest类型规范。常见的问题点:

  • signInContext可能需要补充更多上下文字段(比如ipAddress、userAgent等),仅传递includeApplications可能不足以触发正确的评估逻辑
  • 确认includeApplications中的应用ID是有效的(你传递的00000003-0000-0ff1-ce00-000000000000是Exchange Online的ID,格式正确)
  • 建议使用Microsoft Graph Beta SDK来自动处理序列化,避免手动拼接JSON的错误

3. 使用Microsoft Graph Beta SDK简化请求

手动拼接URL和JSON容易出错,推荐使用Microsoft Graph Beta SDK来封装请求,SDK会自动处理序列化、端点路径和请求头:

步骤1:安装Beta SDK

Install-Package Microsoft.Graph.Beta

步骤2:修改代码使用SDK

using Microsoft.Graph.Beta;
using Microsoft.Graph.Beta.Models;

public async Task<CumulativePolicySettings> RunConditionalAccessWhatIfAsync(string _userId, List<string> _includedApplications)
{
    try
    {
        Logger.Information($"Starting Conditional Access What-If check for user {_userId}", _userId);
        var graphClient = await AzureHttpAuthenticationService.GetAuthenticatedGraphClientAsync();

        var requestBody = new ConditionalAccessEvaluationRequest
        {
            SignInIdentity = new ConditionalAccessEvaluationRequestSignInIdentity
            {
                UserId = _userId
            },
            SignInContext = new ConditionalAccessEvaluationRequestSignInContext
            {
                IncludeApplications = _includedApplications,
                // 补充必要的上下文字段,示例:
                IpAddress = "192.168.1.1",
                UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
            },
            AppliedPoliciesOnly = true
        };

        var evaluationResult = await graphClient.Identity.ConditionalAccess.Evaluate.PostAsync(requestBody);

        var cumulativeSettings = new CumulativePolicySettings();
        foreach (var policy in evaluationResult.Value)
        {
            cumulativeSettings.AllAppliedControls.AddRange(policy.AppliedControls);
            foreach (var setting in policy.Settings.AdditionalData)
            {
                cumulativeSettings.CombinedSettings[setting.Key] = setting.Value;
            }
        }

        Logger.Information("Conditional Access What-If check completed. Policies evaluated: {Count}", evaluationResult.Value.Count);
        return cumulativeSettings;
    }
    catch (Exception ex)
    {
        Logger.Error("Error occurred during Conditional Access What-If check: {Message}", ex.Message);
        return null;
    }
}

// 新增获取GraphClient的方法
public async Task<GraphServiceClient> GetAuthenticatedGraphClientAsync()
{
    var token = await GetAccessTokenAsync();
    return new GraphServiceClient(
        new DelegateAuthenticationProvider((requestMessage) =>
        {
            requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
            return Task.CompletedTask;
        })
    );
}

4. 确认权限配置

确保应用注册已添加Policy.Read.All应用权限并获得管理员同意,这个权限是执行条件访问评估的必要权限。


内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 07:34:50