我正在编写一个Python脚本来编辑存在于SharePoint中的Excel电子表格。我们有Office 365 for Business。我正在使用Microsoft Graph API。 我使用Microsoft Azure Active Directory(AD)注册了Python应用程序,并为Graph API添加了以下2个(仅限应用程序)权限:(1)在所有网站集中读取和写入文件(预览)和(2)读取目录数据。 (我让公司管理员为我注册了应用程序。)
我的Python脚本使用请求库发送REST请求:
import json
import requests
MSGRAPH_URI = 'https://graph.microsoft.com'
VERSION = 'v1.0'
def requestAccessToken(tenant_id, app_id, app_key):
MSLOGIN_URI = 'https://login.microsoftonline.com'
ACCESS_TOKEN_PATH = 'oauth2/token'
GRANT_TYPE = 'client_credentials'
endpoint = '{0}/{1}/{2}'.format(MSLOGIN_URI, tenant_id, ACCESS_TOKEN_PATH)
headers = {'Content-Type': 'Application/Json'}
data = {
'grant_type': GRANT_TYPE,
'client_id': app_id,
'client_secret': app_key,
'resource': MSGRAPH_URI
}
access_token = response.json()['access_token']
return access_token
def getWorkbookID(access_token, fileName):
endpoint = '{0}/{1}/me/drive/root/children'.format(MSGRAPH_URI, VERSION)
headers = {
'Content-Type': 'Application/Json',
'Authorization': 'Bearer {}'.format(access_token)
}
response = requests.get(endpoint, headers=headers)
print response.text
assert response.status_code == 200
items = response.json()['value']
workbook_id = None
for item in items:
if item['name'] == fileName:
workbook_id = item['id']
return workbook_id
access_token = requestAccessToken(TENANT_ID, APP_ID, APP_KEY)
workbook_id = getWorkbookID(access_token, WORKBOOK_FILENAME)
Python应用程序成功地从Microsoft服务器请求并接收access_token
。访问令牌就像这样开始
eyJ0eXAiOiJKV1QiLCJub25jZSI6...
然后它在getWorkbookID()中请求我的文件列表:
GET https://graph.microsoft.com/v1.0/me/drive/root/children
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJub25jZSI6...
这是对该REST请求的响应:
{
"error": {
"code": "InternalServerError",
"message": "Object reference not set to an instance of an object.",
"innerError": {
"request-id": "aa97a822-7ac5-4986-8ac0-9852146e149a",
"date": "2016-12-26T22:13:54"
}
}
}
请注意,当我通过Graph Explorer(https://graph.microsoft.io/en-us/graph-explorer)请求时,我成功获取了我的文件列表。
编辑:
即,
GET https://graph.microsoft.com/v1.0/myOrganization/drive/root/children
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJub25jZSI6...
现在得到以下回复。
{
"error": {
"code": "AccessDenied",
"message": "Either scp or roles claim need to be present in the token.",
"innerError": {
"request-id": "bddb8c51-535f-456b-b43e-5cfdf32bd8a5",
"date": "2016-12-28T22:39:25"
}
}
}
查看graph.microsoft.io/en-us/docs/authorization/app_authorization中的示例,我看到访问令牌响应正文包含"范围"列出在应用程序注册期间为应用授予的权限的属性。但是,我从服务器收到的访问令牌响应没有"范围"属性。这是我的访问令牌响应的样子。
{
"token_type":"Bearer",
"expires_in":"3599",
"ext_expires_in":"0",
"expires_on":"1482968367",
"not_before":"1482964467",
"resource":"https://graph.microsoft.com",
"access_token":"eyJ0eXAiOiJKV..."
}
问题:
答案 0 :(得分:1)
感谢大家的回复。经过更多的研究,我找到了问题的答案。
原始问题:“Microsoft Graph API返回未将对象引用设置为对象实例”
请求
GET https://graph.microsoft.com/v1.0/me/drive/root/children
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJub25jZSI6...
获得回复
{
"error": {
"code": "InternalServerError",
"message": "Object reference not set to an instance of an object.",
"innerError": {
"request-id": "aa97a822-7ac5-4986-8ac0-9852146e149a",
"date": "2016-12-26T22:13:54"
}
}
}
正如@ SriramDhanasekaran-MSFT所指出的那样,/me
指的是当前登录的用户。在我们的示例中,我们没有登录用户,因此我们无法使用/me
。相反,我们可以使用/myOrganization
或不使用任何内容,它是可选的。
更新的问题:“Azure AD”范围“访问令牌响应中缺少的属性”
更新(替换/ me with / myOrganization)请求
GET https://graph.microsoft.com/v1.0/myOrganization/drive/root/children
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJub25jZSI6...
获得回复
{
"error": {
"code": "AccessDenied",
"message": "Either scp or roles claim need to be present in the token.",
"innerError": {
"request-id": "bddb8c51-535f-456b-b43e-5cfdf32bd8a5",
"date": "2016-12-28T22:39:25"
}
}
}
正如@ SriramDhanasekaran-MSFT和@ DanKershaw-MSFT所提到的,access_token
响应缺少scope
属性的原因是管理员未在Azure AD中“授予”权限
然而,@ SriramDhanasekaran-MSFT提供的解决方案:
https://login.microsoftonline.com/common/oauth2/authorize?client_id=&response_type=code&redirect_uri=http://localhost&resource=https://graph.microsoft.com&prompt=consent
对我没用,因为我的应用没有redirect uri
。授予权限的解决方案比这简单:只需让管理员登录到Azure AD并单击“授予权限”链接以授予权限。
此外,/myOrganization/driver/root/children
列出了管理员驱动器的内容。正如@PeterPan-MSFT所指出的,要列出其他用户的驱动器,请将/myOrganization
替换为/users/<user-id>
。
成功:
我的应用程序现在可以在线编辑我的Excel电子表格,而无需人工用户的干预。与@ PeterPan-MSFT所说的相反,使用Graph API可以实现这一点,无需下载Excel电子表格并离线编辑。
要点:
存在两个问题:(1)使用/me
和(2)管理员尚未在Azure AD中授予应用程序权限。
答案 1 :(得分:0)
由于正在使用client_credential令牌流(即,没有经过身份验证的用户上下文),因此/ me的任何请求都无效,因为/ me指的是当前已登录的用户。如果您要访问用户驱动器中的文件,请尝试使用委派令牌。
要在Sharepoint中访问root驱动器,请求url是/ drive / root / children(myorganization是可选的)。
关于遗漏索赔,管理员必须同意该应用程序。您可以通过要求管理员访问以下网址(替换为您应用的网址)来强制同意
https://login.microsoftonline.com/common/oauth2/authorize?client_id=&安培; RESPONSE_TYPE =代码&安培; REDIRECT_URI = http://localhost&resource=https://graph.microsoft.com&prompt=consent
答案 2 :(得分:0)
正如@juunas所说,下面的第一个错误信息应该是.NET中的NULL异常,它在服务器端引起,但也不是API错误或权限问题。
setInterval(function(){ console.log(new Date()); },1000);
您可以参考SO thread了解此案例似乎会针对后端进行更新,请稍后再试。
要解释当您将图谱API网址中的选项error": {
"code": "InternalServerError",
"message": "Object reference not set to an instance of an object.",
更改为me
时的第二个错误,如@ SriramDhanasekaran-MSFT,它会访问当前用户的文件或指定的用户使用myOrganization
而不是<user-id>
。
但是,根据我的理解,您希望编辑SharePoint中的Excel电子表格以进行组织,但似乎不适合使用Graph API。根据我的经验,应该通过使用OneDrive for Business的API将Excel文件复制到本地进行编辑和操作。上传以覆盖它,请参阅the dev documents for OneDrive并尝试使用the API for drive resource。
希望它有所帮助。