我想补充细节,以解决上面我的评论简要提及 - 这将是任何人在Office 365开发多租户应用程序很重要,尤其是如果应用程序将永远访问SharePoint网站,包括OneDrive。
从OAuth 2.0的角度来看,这里的程序有点不标准,但在多租户领域有一定意义。关键是重新使用从Azure返回的第一个CODE。在这里跟我来:
首先,我们按照标准的OAuth认证步骤:
GET /common/oauth2/authorize?client_id=5cb5e93b-57f5-4e09-97c5-e0d20661c59a
&redirect_uri=https://myappdomain.com/v1/oauth2_redirect/
&response_type=code&prompt=login&state=D79E5777 HTTP/1.1
Host: login.windows.net
Cache-Control: no-cache
这重定向到Azure的登录页面,在用户登录如果成功,天青然后调用回你的端点代码。 :
https://myappdomain.com/v1/oauth2_redirect/?code=AAABAAAA...{ONE-CODE-To-RULE-THEM-ALL}xyz
现在我们回发到/token
终端获取的实际承载令牌在后续REST调用中使用。再次,这只是传统的OAuth2 ...但请注意我们如何将/Discovery
端点用作资源 - 而不是我们实际用于收集数据的任何端点。另外,我们要求UserProfile.Read
范围。
POST /common/oauth2/token HTTP/1.1
Host: login.windows.net
Accept: text/json
Cache-Control: no-cache
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="grant_type"
authorization_code
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="code"
AAABAAAA...{ONE-CODE-To-RULE-THEM-ALL}xyz
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="client_id"
5cb5e93b-57f5-4e09-97c5-e0d20661c59a
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="client_secret"
02{my little secret}I=
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="redirect_uri"
https://myappdomain.com/v1/oauth2_redirect/
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="scope"
UserProfile.Read
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="resource"
https://api.office.com/discovery/
----WebKitFormBoundaryE19zNvXGzXaLvS5C
这个主题的响应将包含可用于制造REST调用的/discovery
端点的access-token
。现在
{
"refresh-token": "AAABsvRw-mAAWHr8XOY2lVOKZNLJ{BAR}xkSAA",
"resource": "https://api.office.com/discovery/",
"pwd_exp": "3062796",
"pwd_url": "https://portal.microsoftonline.com/ChangePassword.aspx",
"expires_in": "3599",
"access-token": "ey_0_J0eXAiOiJjsp6PpUhSjpXlm0{F00}-j0aLiFg",
"scope": "Contacts.Read",
"token-type": "Bearer",
"not_before": "1422385173",
"expires_on": "1422389073"
}
,使用这种access-token
,查询/Services
端点找出是Office 365的该用户提供什么。
GET /discovery/v1.0/me/services HTTP/1.1
Host: api.office.com
Cache-Control: no-cache
----WebKitFormBoundaryE19zNvXGzXaLvS5D
Content-Disposition: form-data; name="Authorization"
Bearer ey_0_J0eXAiOiJjsp6PpUhSjpXlm0{F00}-j0aLiFg
----WebKitFormBoundaryE19zNvXGzXaLvS5D
结果将包括一个服务结构数组,描述每个端点的各种端点和功能。
{
"@odata.context": "https://api.office.com/discovery/v1.0/me/$metadata#allServices",
"value": [
{
"capability": "MyFiles",
"entityKey": "[email protected]_SHAREPOINT",
"providerId": "72f988bf-86f1-41af-91ab-2d7cd011db47",
"serviceEndpointUri": "https://contoso-my.sharepoint.com/_api/v1.0/me",
"serviceId": "O365_SHAREPOINT",
"serviceName": "Office 365 SharePoint",
"serviceResourceId": "https://contoso-my.sharepoint.com/"
},
{
"capability": "RootSite",
"entityKey": "[email protected]_SHAREPOINT",
"providerId": "72f988bf-86f1-41af-91ab-2d7cd011db47",
"serviceEndpointUri": "https://contoso.sharepoint.com/_api",
"serviceId": "O365_SHAREPOINT",
"serviceName": "Office 365 SharePoint",
"serviceResourceId": "https://contoso.sharepoint.com/"
},
{
"capability": "Contacts",
"entityKey": "[email protected]_EXCHANGE",
"providerId": "72f988bf-86f1-41af-91ab-2d7cd011db47",
"serviceEndpointUri": "https://outlook.office365.com/api/v1.0",
"serviceId": "O365_EXCHANGE",
"serviceName": "Office 365 Exchange",
"serviceResourceId": "https://outlook.office365.com/"
}
]
}
现在到了棘手的部分...在这一点上,我们知道,我们真的要验证端点 - 其中一些是租户特定的。通常情况下,你会认为我们需要重新演奏这些终结点的OAuth2舞蹈。但是在这种情况下,我们可以使用上面相同的HTTP请求,只是简单地发布与我们最初从Azure收到的代码相同的代码 - 仅使用上述Service结构中的serviceResourceId
和capability
来更改resource
和scope
字段。就像这样:
POST /common/oauth2/token HTTP/1.1
Host: login.windows.net
Accept: text/json
Cache-Control: no-cache
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="grant_type"
authorization_code
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="code"
AAABAAAA...{ONE-CODE-To-RULE-THEM-ALL}xyz
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="client_id"
5cb5e93b-57f5-4e09-97c5-e0d20661c59a
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="client_secret"
02{my little secret}I=
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="redirect_uri"
https://myappdomain.com/v1/oauth2_redirect/
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="scope"
MyFiles.Read
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="resource"
https://contoso-my.sharepoint.com/
----WebKitFormBoundaryE19zNvXGzXaLvS5C
然后做同样的其他两个:
...
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="scope"
RootSite.Read
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="resource"
https://contoso.sharepoint.com/
----WebKitFormBoundaryE19zNvXGzXaLvS5C
和
...
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="scope"
Contacts.Read
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="resource"
https://outlook.office365.com/
----WebKitFormBoundaryE19zNvXGzXaLvS5C
所有这三个调用将导致像第一篇文章的响应上面的,为您提供每个相应端点的刷新令牌和访问令牌。所有这些仅以单一用户身份验证的价格提供。 :)
中提琴!神秘解决了 - 您可以为O365编写多租户应用程序。 :)
啊,最后。经过数小时的研究,实验和开发 - 我偶然发现了一个解决方案!这是Azure/O365 API的一个未记录的“特性”,所以我想确保每个对此主题感兴趣的人都能发现关键:显然通过资源“https://api.office”向Azure端点进行身份验证。com/discovery /“会生成一个可以在POST to/token步骤中多次使用的CODE - 允许您对”discovery/v1.0/me/services“进行REST调用并遍历结果,获取令牌每个人都有相同的代码值。不客气:) – 2015-01-26 20:13:45
回顾:[http://yazezo.com/2013/10/how-to-setup-saas-cloud-multi-tenant.html](How设置一个SaaS云?多租户,CRM 2011,Outlook2010) – 2015-09-25 16:02:46