【问题标题】:Dynamics CRM - Caller not authenticated to serviceDynamics CRM - 呼叫者未通过服务身份验证
【发布时间】:2013-09-10 21:47:51
【问题描述】:

我在 Web 服务器 A 上有一个 MVC4 Web 应用程序,它使用 Web 服务器 B 上的 OrganizationServiceProxy 使用 Dynamics CRM Web 服务。MVC4 应用程序设置为启用了 ASP .NET 模拟和 Windows 身份验证。当我打电话给 WhoAmI 时,我收到一个错误:

'调用者未经服务验证。'

现在,如果我将 MVC4 应用程序移动到具有与 Web 服务器 A 上相同的身份验证的 Web 服务器 B(与 CRM 相同),它会毫无例外地调用 WhoAmI。

这是用于连接服务器的代码。

        string serviceURL = ConfigurationManager.AppSettings["CRMROOTURL"].ToString() + "XRMServices/2011/Organization.svc";

        this.CRMService = GetCRMService(serviceURL);

private OrganizationServiceProxy GetCRMService(string serviceURL)
{
        ClientCredentials credentials = new ClientCredentials();
        credentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;

        OrganizationServiceProxy client
            = new OrganizationServiceProxy(new Uri(serviceURL), null, credentials, null);

        return client;
 }

这是 IIS 网站上的身份验证屏幕截图。

根据正确答案,我只是想提供一些 sn-ps 来帮助其他人。

string loggedUser = System.Security.Principal.WindowsIdentity.GetCurrent().Name;

ClientCredentials credentials = new ClientCredentials();
credentials.Windows.ClientCredential = new NetworkCredential(username, password, domain);

OrganizationServiceProxy client
    = new OrganizationServiceProxy(new Uri(serviceURL), null, credentials, null);

client.ClientCredentials.Windows.ClientCredential = credentials.Windows.ClientCredential;

// -- Retrieve the user.
QueryExpression expression = new QueryExpression
{
    EntityName = "systemuser",
    ColumnSet = new ColumnSet("systemuserid")
};

expression.Criteria.AddCondition("domainname", ConditionOperator.Equal, loggedUser);

EntityCollection ec = client.RetrieveMultiple(expression);

if (ec.Entities.Count > 0)
{
    // -- Impersonate the logged in user.
    client.CallerId = ec.Entities[0].Id;
}

谢谢!

【问题讨论】:

  • 托管 MVC4 Web 应用程序的应用程序池的应用程序标识在两台服务器之间是否不同?
  • 它们目前彼此不同。我应该使它们相同并尝试吗?
  • GetCRMService 真的没有帮助。我需要查看调用 OrganizationServiceProxy 的构造函数的代码,更重要的是,您要传递给它的凭据是什么,以及凭据是如何被实例化的。
  • 对不起,我在帖子中添加了这个功能。
  • 如果在设置 CallerId 之前使用它,请不要使用相同的 OrganizationServiceProxy 对象,这一点非常重要。 callerid 被缓存,您的调用将失败。获得要模拟的用户的 guid 后,您需要创建一个新的 OrganizationServiceProxy 对象并设置该对象的 CallerId。

标签: wcf dynamics-crm-2011


【解决方案1】:

除非您另有明确说明(并且没有任何代码来查看您如何创建 OrganizationServiceProxy),否则本地 OrganizationServiceProxies 将使用当前 AD 帐户(服务帐户的,而不是用户的特定帐户)连接到 CRM。我猜您在服务器 A 上运行的应用程序池不是 CRM 用户,而服务器 B 上的用户是。如果是这样,请将服务器 A 的用户更改为与服务器 B 相同的用户,或者将服务器 A 的用户设置为 CRM 中的用户。

编辑

您正在使用默认网络凭据连接到 CRM。这意味着无论您使用何种 IIS 身份验证,您都将作为应用程序池用户帐户连接到 CRM。只要应用程序池用户是 CRM 用户,这种方法就可以工作,但可能不是您想要的。

您可以使用此方法手动设置网络凭据:

creds.Windows.ClientCredential = new System.Net.NetworkCredential("UserId", "Password", "DomainName");

然后获取 ASP.Net 用户的域名并使用模拟连接到 CRM 以确保正确应用该个人的所有安全性。

【讨论】:

  • 我添加了代码 sn -p 和 IIS 中的身份验证屏幕截图。该错误感觉可能是 Kerbos 的“双跳”问题,但我不确定是否需要 SPN 等来解决它,如果这是问题的话。
  • 这是有道理的,我唯一的问题是我完全理解这一点,如果我将 MVC4 网站与 CRM 网站放在同一台服务器上,为什么它会起作用? IIS 设置与我在远程服务器上的设置完全相同,但在与 CRM 相同的服务器上时,它可以使用登录的 windows 用户(到站点)进行验证和验证。
  • @widmayer 您提到应用程序池的用户在服务器之间的 IIS 中是不同的。不是这样吗?
  • 这种方法奏效了。服务器之间的应用程序池用户不同,我将测试它们是否相同,看看结果是否不同,但我也喜欢使用显式登录的方法,我觉得它提供了更多控制权。
【解决方案2】:

一些愚蠢的事情 - 小心你没有转义你的用户名!

creds.Windows.ClientCredential = new NetworkCredential("domain\user", "PASSWORD");

注意 \u 是一个转义序列 - 您需要输入“domain\user”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-28
    • 2013-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-27
    相关资源
    最近更新 更多