通过 Office 加载项使用 Microsoft Graph 访问 SharePoint (Word JS)
Accessing SharePoint using Microsoft Graph through Office Add-in (Word JS)
我开发了一个 Office.js Word 加载项,并且正在使用 here. It uses the Office.Auth interface
method getAccessTokenAsync
, shown here 所述的 SSO 功能。这按描述工作,但当我尝试使用更多范围使用 Microsoft Graph 访问 SharePoint 时,问题就出现了。
TL;DR
我无法使用 Office.Auth 接口 getAccessTokenAsync
方法生成的令牌成功调用 Microsoft Graph 来访问 SharePoint。
完整描述
我做了以下事情:
- 添加了
Sites.ReadWrite.All
和 Sites.Manage.All
权限
Azure AD 应用程序注册。
在 Word 加载项清单中添加了额外的范围。
<WebApplicationInfo>
<Id>$application_GUID here$</Id>
<Resource>api://localhost:44355/$application_GUID here$</Resource>
<Scopes>
<Scope>Files.Read.All</Scope>
<Scope>Sites.ReadWrite.All</Scope>
<Scope>Sites.Manage.All</Scope>
<Scope>offline_access</Scope>
<Scope>openid</Scope>
<Scope>profile</Scope>
</Scopes>
</WebApplicationInfo>
使用 Graph Explorer 确认我可以制作 SharePoint Graph
打电话,作为我的用户。
GET https://graph.microsoft.com/v1.0/sites/{site-id}/lists/{list-id}/items/{item-id}
在用户未登录 Word 时的 Authorize
方法中添加了附加范围,如 here.
所述
ConfidentialClientApplicationBuilder clientBuilder = ConfidentialClientApplicationBuilder.Create(Settings.AzureADClientId);
clientBuilder.WithClientSecret(Settings.AzureADClientSecret);
clientBuilder.WithRedirectUri(loginRedirectUri.ToString());
clientBuilder.WithAuthority(Settings.AzureADAuthority);
ConfidentialClientApplication clientApp = (ConfidentialClientApplication) clientBuilder.Build();
string[] graphScopes = { "Files.Read.All", "User.Read", "Sites.ReadWrite.All", "Sites.Manage.All" };
// Get and save the token.
var authResultBuilder = clientApp.AcquireTokenByAuthorizationCode(
graphScopes,
Request.Params["code"] // The auth 'code' parameter from the Azure redirect.
);
try
{
var authResult = await authResultBuilder.ExecuteAsync();
ViewBag.AccessToken = authResult.AccessToken;
}
catch (Exception e)
{
ViewBag.Error = e.Message;
}
return View();
有效方法
当用户未登录到 Word 并且必须调用 Authorize
方法时,我能够使用 returned 令牌成功调用我的图形。
什么不起作用
当用户已经登录到 Word 并且加载项 JS 使用 getAccessTokenAsync
方法生成令牌时,我在尝试使用 returned [ 进行相同的图形调用时得到 'Unauthorized' =31=]
问题
我需要为 Office JS getAccessTokenAsync
方法做一些额外的事情来 return 授权令牌以用于我对 SharePoint 的 Graph 调用吗?
编辑Post进一步调查
我使用 jwt.io 解码收到的令牌。
- 登录时使用较旧的
getAccessTokenAsync
方法
(不起作用的场景),我得到一个包含
以下:
{
"aud": $application_GUID$,
"iss": "https://login.microsoftonline.com/$tenant_GUID$/v2.0",
"iat": ...,
"nbf": ...,
"exp": ...,
"aio": ...,
"azp": ...,
"azpacr": "0",
"name": $user_full_name$,
"oid": $GUID$,
"preferred_username": $user_email$,
"scp": "access_as_user",
"sub": ...,
"tid": $tenant_GUID$,
"uti": ...,
"ver": "2.0"
}
- 使用较新的
getAccessToken
方法,两者都在记录时
in并提示登录,(同样不起作用的场景),我
获取包含与上述相同的令牌。
- 随着年龄的增长
getAccessTokenAsync
方法,当提示登录并进入
AzureADAuthController
,(确实有效的场景!),我得到一个
令牌包含以下内容:
{
"aud": "00000003-0000-0000-c000-000000000000",
"iss": "https://sts.windows.net/$tenant_GUID$/",
"iat": ...,
"nbf": ...,
"exp": ...,
"acct": 0,
"acr": "1",
"aio": ...,
"amr": [
"pwd"
],
"app_displayname": "Office-Add-in-ASPNET-SSO",
"appid": $application_GUID$,
"appidacr": "1",
"deviceid": $GUID$,
"family_name": $user_last_name$,
"given_name": $user_first_name$,
"ipaddr": ...,
"name": $user_full_name$,
"oid": $GUID$,
"platf": "3",
"puid": ...,
"scp": "Files.Read.All openid profile Sites.Manage.All Sites.ReadWrite.All User.Read email",
"sub": ...,
"tid": $tenant_GUID$,
"unique_name": $user_email$,
"upn": $user_email$,
"uti": ...,
"ver": "1.0",
"xms_st": {
"sub": ...
},
"xms_tcdt": ...
}
请注意作用域的不同,后者的旧版本具有完整列出的作用域,我可以通过这种方式进行授权。
对此有何解释?
答案不多,但评论太长了:
该示例最近更改为使用新的 OfficeRuntime.auth.getAccessToken
。您似乎使用的是使用 Office.auth.getAccessTokenAsync
的旧版本。这应该仍然有效,但它是一个预览 API,可能会在某个时候停止工作。考虑克隆较新的版本。但是要等几天。我即将对新版本进行一些修复。
检查您是否已将新范围添加到登录操作方法中的 graphScopes
数组。 (除了像您已经完成的那样将它们添加到 Authorize 操作方法中。)
究竟是哪个 HTTP 调用返回 "Unauthorized"?
正在从 getAccessToken
(或 getAccessTokenAsync
)返回什么错误?它通常有一个 13xxx 号码。
2019 年 12 月 19 日更新:
根据您在评论 "To clarify..." 中的描述,您似乎在调用 MS Graph 时包含了从 getAccessToken
获得的令牌。这是行不通的。该令牌是 "bootstrap token"。它使 Office 可以访问您的 add-in 的 Web 应用程序。然后,Web 应用程序需要使用 On Behalf Of Flow 将该令牌交换为允许 Web 应用程序访问 MS Graph 的令牌。然后,您将此 second token 作为 Authorization header 包含在对 Graph 的调用中。您在问题的第一句中链接到的样本就是这样做的。另请参阅这些文章:
最后,确保字符串"Bearer"和Authorizationheader中的token之间有一个空格space。
我开发了一个 Office.js Word 加载项,并且正在使用 here. It uses the Office.Auth interface
method getAccessTokenAsync
, shown here 所述的 SSO 功能。这按描述工作,但当我尝试使用更多范围使用 Microsoft Graph 访问 SharePoint 时,问题就出现了。
TL;DR
我无法使用 Office.Auth 接口 getAccessTokenAsync
方法生成的令牌成功调用 Microsoft Graph 来访问 SharePoint。
完整描述
我做了以下事情:
- 添加了
Sites.ReadWrite.All
和Sites.Manage.All
权限 Azure AD 应用程序注册。 在 Word 加载项清单中添加了额外的范围。
<WebApplicationInfo> <Id>$application_GUID here$</Id> <Resource>api://localhost:44355/$application_GUID here$</Resource> <Scopes> <Scope>Files.Read.All</Scope> <Scope>Sites.ReadWrite.All</Scope> <Scope>Sites.Manage.All</Scope> <Scope>offline_access</Scope> <Scope>openid</Scope> <Scope>profile</Scope> </Scopes> </WebApplicationInfo>
使用 Graph Explorer 确认我可以制作 SharePoint Graph 打电话,作为我的用户。
GET https://graph.microsoft.com/v1.0/sites/{site-id}/lists/{list-id}/items/{item-id}
在用户未登录 Word 时的
所述Authorize
方法中添加了附加范围,如 here.ConfidentialClientApplicationBuilder clientBuilder = ConfidentialClientApplicationBuilder.Create(Settings.AzureADClientId); clientBuilder.WithClientSecret(Settings.AzureADClientSecret); clientBuilder.WithRedirectUri(loginRedirectUri.ToString()); clientBuilder.WithAuthority(Settings.AzureADAuthority); ConfidentialClientApplication clientApp = (ConfidentialClientApplication) clientBuilder.Build(); string[] graphScopes = { "Files.Read.All", "User.Read", "Sites.ReadWrite.All", "Sites.Manage.All" }; // Get and save the token. var authResultBuilder = clientApp.AcquireTokenByAuthorizationCode( graphScopes, Request.Params["code"] // The auth 'code' parameter from the Azure redirect. ); try { var authResult = await authResultBuilder.ExecuteAsync(); ViewBag.AccessToken = authResult.AccessToken; } catch (Exception e) { ViewBag.Error = e.Message; } return View();
有效方法
当用户未登录到 Word 并且必须调用 Authorize
方法时,我能够使用 returned 令牌成功调用我的图形。
什么不起作用
当用户已经登录到 Word 并且加载项 JS 使用 getAccessTokenAsync
方法生成令牌时,我在尝试使用 returned [ 进行相同的图形调用时得到 'Unauthorized' =31=]
问题
我需要为 Office JS getAccessTokenAsync
方法做一些额外的事情来 return 授权令牌以用于我对 SharePoint 的 Graph 调用吗?
编辑Post进一步调查
我使用 jwt.io 解码收到的令牌。
- 登录时使用较旧的
getAccessTokenAsync
方法 (不起作用的场景),我得到一个包含 以下:
{
"aud": $application_GUID$,
"iss": "https://login.microsoftonline.com/$tenant_GUID$/v2.0",
"iat": ...,
"nbf": ...,
"exp": ...,
"aio": ...,
"azp": ...,
"azpacr": "0",
"name": $user_full_name$,
"oid": $GUID$,
"preferred_username": $user_email$,
"scp": "access_as_user",
"sub": ...,
"tid": $tenant_GUID$,
"uti": ...,
"ver": "2.0"
}
- 使用较新的
getAccessToken
方法,两者都在记录时 in并提示登录,(同样不起作用的场景),我 获取包含与上述相同的令牌。 - 随着年龄的增长
getAccessTokenAsync
方法,当提示登录并进入AzureADAuthController
,(确实有效的场景!),我得到一个 令牌包含以下内容:
{
"aud": "00000003-0000-0000-c000-000000000000",
"iss": "https://sts.windows.net/$tenant_GUID$/",
"iat": ...,
"nbf": ...,
"exp": ...,
"acct": 0,
"acr": "1",
"aio": ...,
"amr": [
"pwd"
],
"app_displayname": "Office-Add-in-ASPNET-SSO",
"appid": $application_GUID$,
"appidacr": "1",
"deviceid": $GUID$,
"family_name": $user_last_name$,
"given_name": $user_first_name$,
"ipaddr": ...,
"name": $user_full_name$,
"oid": $GUID$,
"platf": "3",
"puid": ...,
"scp": "Files.Read.All openid profile Sites.Manage.All Sites.ReadWrite.All User.Read email",
"sub": ...,
"tid": $tenant_GUID$,
"unique_name": $user_email$,
"upn": $user_email$,
"uti": ...,
"ver": "1.0",
"xms_st": {
"sub": ...
},
"xms_tcdt": ...
}
请注意作用域的不同,后者的旧版本具有完整列出的作用域,我可以通过这种方式进行授权。
对此有何解释?
答案不多,但评论太长了:
该示例最近更改为使用新的 OfficeRuntime.auth.getAccessToken
。您似乎使用的是使用 Office.auth.getAccessTokenAsync
的旧版本。这应该仍然有效,但它是一个预览 API,可能会在某个时候停止工作。考虑克隆较新的版本。但是要等几天。我即将对新版本进行一些修复。
检查您是否已将新范围添加到登录操作方法中的 graphScopes
数组。 (除了像您已经完成的那样将它们添加到 Authorize 操作方法中。)
究竟是哪个 HTTP 调用返回 "Unauthorized"?
正在从 getAccessToken
(或 getAccessTokenAsync
)返回什么错误?它通常有一个 13xxx 号码。
2019 年 12 月 19 日更新:
根据您在评论 "To clarify..." 中的描述,您似乎在调用 MS Graph 时包含了从 getAccessToken
获得的令牌。这是行不通的。该令牌是 "bootstrap token"。它使 Office 可以访问您的 add-in 的 Web 应用程序。然后,Web 应用程序需要使用 On Behalf Of Flow 将该令牌交换为允许 Web 应用程序访问 MS Graph 的令牌。然后,您将此 second token 作为 Authorization header 包含在对 Graph 的调用中。您在问题的第一句中链接到的样本就是这样做的。另请参阅这些文章:
最后,确保字符串"Bearer"和Authorizationheader中的token之间有一个空格space。