c# - 您如何使用 ADAL/OAuth 对 CRM Online 进行身份验证并通过 token 请求数据?

标签 c# oauth azure-active-directory dynamics-crm-online

我有多个 CRM Online 实例,它们由 Microsoft 托管在云中。
它们都受到同一个 Azure Active Directory 的保护,该 Azure Active Directory 本身由 ADFS 管理。
我的应用程序在 Azure AD 中注册,因此具有客户端 ID/ key 等和 CRM 权限。

我想通过 Web API 连接到特定的 CRM 实例以请求数据。
我可以通过将 CrmServiceClient 与包含用户名/密码的连接字符串一起使用来实现此功能。
这似乎是常见的记录示例,但我不想这样做。以下 MSDN 文章使我看起来可以通过 token 来完成:https://msdn.microsoft.com/en-us/library/gg327838.aspx

我可以像这样成功获得 token (为了安全我已经隐藏了一些细节):

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);

通常我会将此 token 作为身份验证 header 传递给 HttpRequest,但此博客上的选项 3 建议可以改用 SDK 提供的 OrganizationWebProxyClient 类: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 中创建一个绑定(bind):

<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

我被引导相信这个错误实际上吞没了真正的错误是什么(感谢微软)所以我不知道真正的错误是什么。
很多在线文档都说是客户端和服务器时间不同步,但我不认为是这样。我无法证明微软服务器的运行时间,但我的时钟绝对准确,而且在英国的正确时区。

有人知道我做错了什么吗?
或者,有没有其他方法可以在没有用户名/密码的情况下进行身份验证?
还是我只是找错了树,我到底应该使用用户名/密码吗?

最佳答案

CRM Online 似乎不支持任何类型的匿名或被动身份验证,必须始终提供有效的用户名和密码。

我只是简单地为 API 访问创建了一个用户,并使用这些凭据通过 CRM 进行身份验证。虽然这不是我想要的,但它确实可以正常工作。

我希望有人能证明我是错的,但现在看来这是不可能的。

关于c# - 您如何使用 ADAL/OAuth 对 CRM Online 进行身份验证并通过 token 请求数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38595082/

相关文章:

php - Oauth2-server-laravel 自定义消息响应

java - AWS API 网关 + AWS ECS + OAuth2 密码授予

angularjs - 如何在 Id_token 中包含首选用户名声明

oauth - 用于获取用户名字和姓氏的 Google OAuth 范围参数

azure - 在 Azure 中,如何使两个事件目录共享同一个应用程序?

azure - 向 Microsoft Authenticator 应用程序异步推送通知

c# - 从 App WinRT 获取本地文件夹

c# - 将下划线编码为 %5F

c# - 上下文菜单继续使用Mvvm获取错误的对象

c# - Span<T> 是否可以在没有固定表达式的情况下指向固定大小的缓冲区?