我们在2016年使用odata v8.1端点成功impersonate a user.
请注意,预期的请求流程为:邮递员 - > LocalHost微服务 - > CRM
来自 Postman - > CRM 的工作请求示例(直接,无需通过微服务)
Accept:application/json
Content-Type:application/json; charset=utf-8
OData-MaxVersion:4.0
OData-Version:4.0
MSCRMCallerID:d994d6ff-5531-e711-9422-00155dc0d345
Cache-Control:no-cache
反对odata终点:..../api/data/v8.1/leads
请注意,仅当通过postman直接针对odata v8.1端点发出时,此操作才会成功。
当尝试执行相同操作时,让本地服务(邮递员 - > LocalHost服务 - > CRM),这会失败,并且只是忽略??? MSCRMCallerID标头。
检查从Postman传递给LocalHost微服务的标头时,请求,由VS 2017中的调试器检查:
{Method: POST, RequestUri: 'https://.../api/data/v8.1/leads', Version: 1.1, Content: System.Net.Http.StringContent, Headers:
{
OData-Version: 4.0
OData-MaxVersion: 4.0
MSCRMCallerID: D994D6FF-5531-E711-9422-00155DC0D345
Cache-Control: no-cache
Accept: application/json
Content-Type: application/json; charset=utf-8
}}
记录是成功创建的,但是在CreatedBy字段上是服务用户名而不是MSCRMCallerID用户名(d994d6ff-5531-e711-9422-00155dc0d345),并且CreatedOnBehalf字段为空。
我们做错了什么?
我们如何通过我们的服务进行此模拟?
编辑+更多信息
请注意,我相信我已经包含了所有相关信息,但如果我没有,请告诉我在这个问题上我应该提供哪些其他输入。
我尝试了什么?
请注意,此小提琴曲线是显示 Postman - >的曲线。微服务请求。 它没有显示从localhost微服务到CRM的通信。(我不知道为什么,也许是因为它是加密的)
POST https://localhost:19081/.....Leads/API/leads HTTP/1.1
Host: localhost:19081
Connection: keep-alive
Content-Length: 84
Cache-Control: no-cache
Origin: chrome-extension://aicmkgpgakddgnaphhhpliifpcfhicfo
MSCRMCallerID: D994D6FF-5531-E711-9422-00155DC0D345
X-Postman-Interceptor-Id: d79b1d2e-2155-f2ec-4ad7-e9b63e7fb90d
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
Content-Type: application/json; charset=UTF-8
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8
Cookie: ai_user=Ka2Xn|2017-05-25T17:30:57.941Z
{
"subject": "created by mscrmcaller user2: d994d6ff-5531-e711-9422-00155dc0d345"
}
@Ram建议我们使用组织服务进行身份验证,这是一个选项,考虑到我们是针对Web API执行的吗?请求的令牌是否仍然有效。 (请注意,这可能是一个愚蠢的问题,原因是因为我不了解身份验证的工作原理。)
以下是我们如何在每次通话上对当前进行身份验证时的代码段:
//check headers to see if we got a redirect to the new location
var shouldAuthenticate = redirectUri.AbsoluteUri.Contains("adfs/ls");
if (!shouldAuthenticate)
{
return;
}
var adfsServerName = redirectUri.Authority;
var queryParams = HttpUtility.ParseQueryString(redirectUri.Query);
ServicePointManager.ServerCertificateValidationCallback +=
(sender, cert, chain, sslPolicyErrors) => true;
WSTrustChannelFactory factory = null;
try
{
// use a UserName Trust Binding for username authentication
factory = new WSTrustChannelFactory(
new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
$"https://{adfsServerName}/adfs/services/trust/13/usernamemixed")
{
Credentials =
{
UserName =
{
UserName = $"{credential.Domain}\\{credential.UserName}",
Password = credential.Password
}
},
TrustVersion = TrustVersion.WSTrust13
};
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
AppliesTo = new EndpointReference(_client.BaseAddress.AbsoluteUri),
TokenType = "urn:oasis:names:tc:SAML:1.0:assertion",
KeyType = KeyTypes.Bearer
};
var channel = factory.CreateChannel();
channel.Issue(rst, out RequestSecurityTokenResponse rstr);
var fedSerializer = new WSFederationSerializer();
var rstrContent = fedSerializer.GetResponseAsString(rstr, new WSTrustSerializationContext());
// construct a authentication form
var crmauthenticaionPostDictionary = new Dictionary<string, string>
{
{"wa", queryParams["wa"]},
{"wresult", rstrContent},
{"wctx", queryParams["wctx"]}
};
// post the authentication form to the website.
var crmAuthorizationPostResponse = _client.PostAsync(_client.BaseAddress.AbsoluteUri, new FormUrlEncodedContent(crmauthenticaionPostDictionary)).Result;
var crmAuthorizationPostResponseString = crmAuthorizationPostResponse.Content.ReadAsStringAsync().Result;
//we should be authenticated here
if (
!(
// we are correctly authorized if we got redirected to the correct address that we
// were trying to reach in the first place.
crmAuthorizationPostResponse.StatusCode == HttpStatusCode.Redirect
&& crmAuthorizationPostResponse.Headers.Location == authenticationTestUri
)
)
{
throw new Exception("ADFS Authentication to CRM failed.");
}
答案 0 :(得分:3)
当你做Postman to CRM请求时,它的直接电话&amp; CRM以预期的方式处理它。
但是在Postman中 - &gt;微服务 - &gt; CRM,微软服务与CRM之间的标头迷失了。
在您的微服务中,您必须手动将标头处理到CRM SDK调用。
HttpWebRequest myHttpWebRequest1= (HttpWebRequest)WebRequest.Create(uri);
myHttpWebRequest1.Headers.Add("MSCRMCallerID", "D994D6FF-5531-E711-9422-00155DC0D345");
或HTTP Header Forwarding(抱歉,我找不到Azure / C#)
更新
假设您正在关注此MSDN samples在c#microservice中进行CRM Web api调用。我已经包含了我们需要的标头 - MSCRMCallerID。看看它是否对你有帮助。
public async Task BasicCreateAndUpdatesAsync()
{
Console.WriteLine("--Section 1 started--");
string queryOptions; //select, expand and filter clauses
//First create a new contact instance, then add additional property values and update
// several properties.
//Local representation of CRM Contact instance
contact1.Add("firstname", "Peter");
contact1.Add("lastname", "Cambel");
HttpRequestMessage createRequest1 =
new HttpRequestMessage(HttpMethod.Post, getVersionedWebAPIPath() + "contacts");
createRequest1.Content = new StringContent(contact1.ToString(),
Encoding.UTF8, "application/json");
createRequest1.Headers.Add("MSCRMCallerID", "D994D6FF-5531-E711-9422-00155DC0D345");
HttpResponseMessage createResponse1 =
await httpClient.SendAsync(createRequest1);
if (createResponse1.StatusCode == HttpStatusCode.NoContent) //204
{
Console.WriteLine("Contact '{0} {1}' created.",
contact1.GetValue("firstname"), contact1.GetValue("lastname"));
contact1Uri = createResponse1.Headers.
GetValues("OData-EntityId").FirstOrDefault();
entityUris.Add(contact1Uri);
Console.WriteLine("Contact URI: {0}", contact1Uri);
}
else
{
Console.WriteLine("Failed to create contact for reason: {0}",
createResponse1.ReasonPhrase);
throw new CrmHttpResponseException(createResponse1.Content);
}
}
答案 1 :(得分:2)
在冒充
时,你必须小心谨慎<强> 1。要模拟用户,请在实例上设置CallerId属性 在调用服务的Web方法之前的OrganizationServiceProxy。
<强> 2。用户(模仿者)必须具有ActOnBehalfOf权限,或者是Active Directory中PrivUserGroup组的成员
代码示例
SystemUser user = null;
user = new SystemUser(systemUser);
OrganizationServiceProxy service = CrmService.Proxy;
service.CallerID = user.Id;
由于您的代码不可用,请确保正确设置上述所有字段