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

如何通过单次登录提示获取SharePoint API与Graph API双令牌(Kotlin)

在Kotlin中单次登录获取Graph和SharePoint API令牌的解决方案

核心结论

可以通过单次用户登录授权同时获取访问两个API的权限,但单次令牌请求只能返回一个资源的访问令牌。你遇到的「不存在的作用域」错误,本质是混合了不同资源URI的作用域格式,导致Azure AD无法识别。

错误原因分析

Graph API和SharePoint API的作用域属于不同的资源URI:

  • Graph的作用域格式为 https://graph.microsoft.com/<权限>(如https://graph.microsoft.com/User.Read)
  • SharePoint的作用域格式为 https://<你的租户域名>.sharepoint.com/<权限>(如https://contoso.sharepoint.com/Sites.Read.All)

如果直接把两种不带资源前缀的权限(比如User.Read + Sites.Read.All)混合,或者格式错误,Azure AD会判定为无效作用域,抛出错误。

具体实现步骤

1. 配置Azure AD应用权限

在Azure AD应用注册中:

  • 添加Graph API的所需权限(如User.Read、Files.Read)
  • 添加SharePoint Online的所需权限(如Sites.Read.All,注意选择「SharePoint」类别下的权限,而非Graph中的SharePoint权限)
  • 对租户级权限完成管理员同意

2. 单次登录获取刷新令牌

发起登录请求时,指定包含两个API权限的作用域列表,同时加上offline_access以获取刷新令牌(用于后续兑换其他资源的令牌):

// 替换为你的租户域名和所需权限
val scopes = listOf(
    "https://graph.microsoft.com/.default",
    "https://contoso.sharepoint.com/.default",
    "offline_access"
)

// 以MSAL for Android为例初始化客户端
val pca = PublicClientApplication.create(
    context,
    "<你的客户端ID>",
    Authority.create("https://login.microsoftonline.com/<你的租户ID>")
)

// 发起登录请求
val authParams = AcquireTokenParameters.Builder()
    .startAuthorizationFromActivity(activity)
    .withScopes(scopes)
    .withCallback(object : AuthenticationCallback {
        override fun onSuccess(result: IAuthenticationResult) {
            // 保存刷新令牌和账户信息,用于后续获取SharePoint令牌
            val refreshToken = result.refreshToken
            val account = result.account
        }

        override fun onError(e: MsalException) { /* 处理错误 */ }
        override fun onCancel() { /* 用户取消登录 */ }
    })
    .build()

pca.acquireToken(authParams)

登录成功后,你会得到Graph API的访问令牌,以及一个可用于兑换SharePoint令牌的刷新令牌。

3. 用刷新令牌获取SharePoint访问令牌

无需再次提示用户登录,直接通过刷新令牌静默获取SharePoint的令牌:

val silentParams = AcquireTokenSilentParameters.Builder()
    .withScopes(listOf("https://contoso.sharepoint.com/.default"))
    .withAccount(account) // 从登录结果中获取的账户
    .withForceRefresh(false)
    .withCallback(object : SilentAuthenticationCallback {
        override fun onSuccess(result: IAuthenticationResult) {
            val sharePointToken = result.accessToken
            // 使用该令牌调用SharePoint API
        }

        override fun onError(e: MsalException) {
            // 仅当权限变更等特殊情况时需要重新授权
        }
    })
    .build()

pca.acquireTokenSilentAsync(silentParams)

关键注意事项

  • 始终使用完整的资源前缀定义作用域,避免省略https://<租户域名>.sharepoint.com/或https://graph.microsoft.com/
  • offline_access作用域是获取刷新令牌的必要条件,没有它无法后续静默获取其他资源的令牌
  • 确保应用注册的权限已正确配置并完成管理员同意,否则会出现权限不足的错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 20:40:18