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

如何为应用而非用户授权REST API?移动端调用Graph API遇401错误

解决401未授权:获取应用身份令牌调用Microsoft Graph API

问题原因

你当前使用的是用户上下文的委派权限令牌,但调用bookingBusinesses/appointments API需要使用应用权限令牌(以应用身份而非用户身份发起请求),因此返回401未授权错误。

前置确认

  1. 你的Azure AD应用已添加Microsoft Graph的应用权限(而非委派权限),比如BookingsAppointment.Read.All、BookingsAppointment.ReadWrite.All等,且已完成管理员同意(应用权限必须由租户管理员批准生效)。
  2. 应用注册中已生成客户端密码(Client Secret)或证书,用于应用身份验证。

实现步骤:用客户端凭据流获取应用令牌

推荐使用Microsoft官方的Microsoft.Identity.Client库处理令牌获取,避免手动实现OAuth流程的错误。

  1. 安装NuGet包:
Install-Package Microsoft.Identity.Client
  1. 编写令牌获取方法:
using Microsoft.Identity.Client;

public async Task<string> GetAppAccessTokenAsync(string tenantId, string clientId, string clientSecret)
{
    var app = ConfidentialClientApplicationBuilder
        .Create(clientId)
        .WithClientSecret(clientSecret)
        .WithAuthority($"https://login.microsoftonline.com/{tenantId}")
        .Build();

    // .default 表示使用应用注册中已配置的所有应用权限
    var scopes = new[] { "https://graph.microsoft.com/.default" };

    var authResult = await app.AcquireTokenForClient(scopes)
        .ExecuteAsync()
        .ConfigureAwait(false);

    return authResult.AccessToken;
}
  1. 修改API调用代码:
// 替换为你的实际配置
string tenantId = "你的Azure AD租户ID";
string clientId = "应用注册的客户端ID";
string clientSecret = "应用的客户端密码";
string adTenantId = "你的Booking Business租户ID";

// 获取应用令牌
string accessToken = await GetAppAccessTokenAsync(tenantId, clientId, clientSecret).ConfigureAwait(false);

// 调用Graph API
string url = $@"https://graph.microsoft.com/v1.0/solutions/bookingBusinesses/{adTenantId}/appointments";

using HttpClient client = new();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
HttpResponseMessage response = await client.GetAsync(url).ConfigureAwait(false);

// 处理响应
if (response.IsSuccessStatusCode)
{
    var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
    // 解析返回的预约数据
}
else
{
    // 输出错误详情排查
    var errorDetails = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
    Console.WriteLine($"请求失败:{response.StatusCode}\n错误详情:{errorDetails}");
}

重要安全提示

移动应用属于公开客户端,无法安全存储客户端密码,直接在移动应用中使用客户端凭据流会导致密码泄露风险。建议架构调整为:

  • 搭建自己的后端服务,由后端使用客户端凭据流获取应用令牌并调用Graph API
  • 移动应用仅调用你的后端API,由后端中转处理Graph请求

内容的提问来源于stack exchange,提问作者David Shochet

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 08:10:55