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

Microsoft Graph Kotlin客户端身份验证失败,请求匹配bash脚本逻辑

解决方案

问题核心在于MS Graph SDK默认的ClientCredentialProvider强制要求客户端凭据流的scope以/.default结尾,但你的bash脚本是通过指定resource为Graph服务、搭配自定义scope来获取有效令牌的。要复刻bash的逻辑,需要手动构建令牌请求,再用该令牌初始化Graph客户端。

步骤1:手动获取符合要求的访问令牌

直接向AAD的v1.0令牌端点发送POST请求,参数完全对齐你的bash脚本:

import okhttp3.FormBody
import okhttp3.OkHttpClient
import okhttp3.Request
import com.google.gson.JsonObject
import com.google.gson.JsonParser

fun getAccessToken(): String {
    val client = OkHttpClient()
    val formBody = FormBody.Builder()
        .add("grant_type", "client_credentials")
        .add("client_id", "你的客户端ID")
        .add("client_secret", "你的客户端密钥")
        .add("resource", "https://graph.microsoft.com")
        .add("scope", "api://ourApp/2023/CustomScope")
        .build()

    val request = Request.Builder()
        .url("https://login.microsoftonline.com/你的租户ID/oauth2/token")
        .post(formBody)
        .build()

    client.newCall(request).execute().use { response ->
        if (!response.isSuccessful) throw RuntimeException("令牌获取失败:${response.code}")
        val responseBody = response.body?.string() ?: throw RuntimeException("令牌响应为空")
        val json = JsonParser.parseString(responseBody).asJsonObject
        return json.get("access_token").asString
    }
}

步骤2:用令牌初始化GraphServiceClient

使用SimpleAuthenticationProvider传入手动获取的令牌,替代SDK默认的凭据提供者:

import com.microsoft.graph.authentication.SimpleAuthenticationProvider
import com.microsoft.graph.requests.GraphServiceClient
import okhttp3.OkHttpClient

fun buildGraphClient(): GraphServiceClient<OkHttpClient> {
    val authProvider = object : SimpleAuthenticationProvider() {
        override fun getAuthorizationTokenAsync(requestUrl: String): String {
            return getAccessToken() // 实际使用中建议添加令牌缓存逻辑,避免重复请求
        }
    }
    return GraphServiceClient.builder()
        .authenticationProvider(authProvider)
        .buildClient()
}

步骤3:调用API获取应用角色分配

现在可以正常调用Graph API获取目标数据:

fun main() {
    val graphClient = buildGraphClient()
    val appRoleAssignments = graphClient.servicePrincipals("你的服务主体ID").appRoleAssignments().buildRequest().get()
    println("获取到${appRoleAssignments.count()}条应用角色分配记录")
    appRoleAssignments.forEach { assignment ->
        println("分配ID:${assignment.id},资源ID:${assignment.resourceId}")
    }
}

关键说明

  • 你的bash脚本本质是使用AAD v1.0 OAuth2端点,通过resource参数绑定Graph服务,同时用自定义scope获取包含对应权限的令牌。SDK默认的ClientCredentialProvider基于v2.0端点,不支持这种resource+自定义scope的组合,因此需要手动模拟v1.0请求。
  • 务必添加令牌缓存逻辑:示例中每次请求都获取新令牌,实际使用时应从令牌响应的expires_in字段计算过期时间,缓存令牌直到过期后再重新请求。
  • 确认你的应用注册在Azure AD中已被授予使用该自定义scope的权限,否则即使获取到令牌,Graph API仍会返回权限不足的错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 14:22:40