您如何使用 ADAL/OAuth 通过 CRM Online 进行身份验证并通过令牌请求数据?
How can you authenticate with CRM Online using ADAL/OAuth and request data via a token?
我有多个由 Microsoft 托管在云中的 CRM Online 实例。
它们都受到同一个 Azure Active Directory 的保护,而 Azure Active Directory 本身由 ADFS 管理。
我的应用程序在 Azure AD 中注册,因此具有客户端 ID/key 等和 CRM 权限。
我想通过 Web 连接到特定的 CRM 实例 API 以请求数据。
我可以通过将 CrmServiceClient
与包含 username/password.
的连接字符串一起使用来实现此目的
这似乎是常见的记录示例,但我不想这样做。以下 MSDN 文章使我看起来可以通过令牌来完成:https://msdn.microsoft.com/en-us/library/gg327838.aspx
我可以像这样成功获得令牌(为了安全我已经隐藏了一些细节):
var tenantName = @"myorg.onmicrosoft.com";
var authString = string.Format(@"https://login.microsoftonline.com/{0}", tenantName);
var authContext = new AuthenticationContext(authString, false);
// I am in the UK so use crm4
var resource = @"https://myorg.crm4.dynamics.com";
var clientId = @"899ac540-2134-1234-abcd-2d6440046630";
var key = @"nStbgtfe0oybU1P5+/FQ4wFn1oLTEDr5M7Kjrghf5yh=";
var clientCred = new ClientCredential(clientId, key);
var authResult = await authContext.AcquireTokenAsync(resource, clientCred);
通常我会将此令牌作为身份验证传递给 HttpRequest header 但此博客上的选项 3 建议可以使用 SDK 提供的 OrganizationWebProxyClient
class : http://crmtipoftheday.com/2015/06/24/you-have-oauth-token-now-what/
var orgService = new OrganizationWebProxyClient(
new Uri("https://myorg.api.crm4.dynamics.com/XRMServices/2011/Organization.svc"), false)
{
HeaderToken = authResult.AccessToken,
SdkClientVersion = "8"
};
最后我需要添加对 Microsoft 提供的组织服务的服务引用:
https://myorg.api.crm4.dynamics.com/XRMServices/2011/Organization.svc?singleWSDL&sdkversion=8
这在我的 app.config:
中创建了一个绑定
<system.serviceModel>
<bindings>
<customBinding>
<binding name="CustomBinding_IOrganizationService">
<textMessageEncoding />
<httpsTransport />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="https://myorg.api.crm4.dynamics.com/XRMServices/2011/Organization.svc"
binding="customBinding" bindingConfiguration="CustomBinding_IOrganizationService"
contract="CRMOrgService.IOrganizationService" name="CustomBinding_IOrganizationService" />
</client>
</system.serviceModel>
然后我可以将其分配给组织服务:
var binding = new CustomBinding("CustomBinding_IOrganizationService");
orgService.Endpoint.Binding = binding;
我终于可以调用网络服务了:
var contacts = orgService.RetrieveMultiple(new QueryExpression
{
EntityName = "contact",
ColumnSet = new ColumnSet("firstname", "lastname")
})
.Entities
.Select(item => item.ToEntity<Contact>());
但是在调用组织服务时出现错误:
An error occurred when verifying security for the message
我被引导相信这个错误实际上吞没了真正的错误是什么(感谢微软)所以我不知道真正的问题是什么。
很多在线文档都说是客户端和服务器时间不同步,但我不认为是这样。我无法证明微软服务器的运行时间,但我的时钟绝对准确,而且在英国的正确时区。
有人知道我做错了什么吗?
或者有没有不同的方式来验证没有 username/password?
还是我只是找错了树,我到底应该使用 username/password 吗?
CRM Online 似乎不支持任何类型的匿名或被动身份验证,必须始终提供有效的用户名和密码。
我只为 API 访问创建了一个用户,并使用这些凭据通过 CRM 进行身份验证。虽然这不是我想要的,但它确实可以正常工作。
我希望有人能证明我是错的,但现在看来这不可能。
我有多个由 Microsoft 托管在云中的 CRM Online 实例。
它们都受到同一个 Azure Active Directory 的保护,而 Azure Active Directory 本身由 ADFS 管理。
我的应用程序在 Azure AD 中注册,因此具有客户端 ID/key 等和 CRM 权限。
我想通过 Web 连接到特定的 CRM 实例 API 以请求数据。
我可以通过将 CrmServiceClient
与包含 username/password.
的连接字符串一起使用来实现此目的
这似乎是常见的记录示例,但我不想这样做。以下 MSDN 文章使我看起来可以通过令牌来完成:https://msdn.microsoft.com/en-us/library/gg327838.aspx
我可以像这样成功获得令牌(为了安全我已经隐藏了一些细节):
var tenantName = @"myorg.onmicrosoft.com";
var authString = string.Format(@"https://login.microsoftonline.com/{0}", tenantName);
var authContext = new AuthenticationContext(authString, false);
// I am in the UK so use crm4
var resource = @"https://myorg.crm4.dynamics.com";
var clientId = @"899ac540-2134-1234-abcd-2d6440046630";
var key = @"nStbgtfe0oybU1P5+/FQ4wFn1oLTEDr5M7Kjrghf5yh=";
var clientCred = new ClientCredential(clientId, key);
var authResult = await authContext.AcquireTokenAsync(resource, clientCred);
通常我会将此令牌作为身份验证传递给 HttpRequest header 但此博客上的选项 3 建议可以使用 SDK 提供的 OrganizationWebProxyClient
class : http://crmtipoftheday.com/2015/06/24/you-have-oauth-token-now-what/
var orgService = new OrganizationWebProxyClient(
new Uri("https://myorg.api.crm4.dynamics.com/XRMServices/2011/Organization.svc"), false)
{
HeaderToken = authResult.AccessToken,
SdkClientVersion = "8"
};
最后我需要添加对 Microsoft 提供的组织服务的服务引用:
https://myorg.api.crm4.dynamics.com/XRMServices/2011/Organization.svc?singleWSDL&sdkversion=8
这在我的 app.config:
中创建了一个绑定<system.serviceModel>
<bindings>
<customBinding>
<binding name="CustomBinding_IOrganizationService">
<textMessageEncoding />
<httpsTransport />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="https://myorg.api.crm4.dynamics.com/XRMServices/2011/Organization.svc"
binding="customBinding" bindingConfiguration="CustomBinding_IOrganizationService"
contract="CRMOrgService.IOrganizationService" name="CustomBinding_IOrganizationService" />
</client>
</system.serviceModel>
然后我可以将其分配给组织服务:
var binding = new CustomBinding("CustomBinding_IOrganizationService");
orgService.Endpoint.Binding = binding;
我终于可以调用网络服务了:
var contacts = orgService.RetrieveMultiple(new QueryExpression
{
EntityName = "contact",
ColumnSet = new ColumnSet("firstname", "lastname")
})
.Entities
.Select(item => item.ToEntity<Contact>());
但是在调用组织服务时出现错误:
An error occurred when verifying security for the message
我被引导相信这个错误实际上吞没了真正的错误是什么(感谢微软)所以我不知道真正的问题是什么。
很多在线文档都说是客户端和服务器时间不同步,但我不认为是这样。我无法证明微软服务器的运行时间,但我的时钟绝对准确,而且在英国的正确时区。
有人知道我做错了什么吗?
或者有没有不同的方式来验证没有 username/password?
还是我只是找错了树,我到底应该使用 username/password 吗?
CRM Online 似乎不支持任何类型的匿名或被动身份验证,必须始终提供有效的用户名和密码。
我只为 API 访问创建了一个用户,并使用这些凭据通过 CRM 进行身份验证。虽然这不是我想要的,但它确实可以正常工作。
我希望有人能证明我是错的,但现在看来这不可能。