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

