Подтвердить что ты не робот

Как олицетворять пользователя через odata

Мы успешно использовали одату odata v8.1 в 2016 году, чтобы олицетворять пользователя.

Обратите внимание, что предполагаемый поток запросов: Почтальон → LocalHost Microservice → 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

Против конечной точки одаты: ..../api/data/v8.1/leads

Обратите внимание, что это было успешным только тогда, когда оно выдается непосредственно против конечной точки odata v8.1 через postman.

При попытке сделать то же самое, если служба работает локально (Postman → LocalHost Service → CRM), это не удается и просто игнорирует??? заголовок MSCRMCallerID.

После изучения заголовков, которые были переданы в LocalHost Microservice из Postman, запрос, рассмотренный отладчиком в 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
}}

Запись создается успешно, однако в поле CreateBy указано имя пользователя службы NOT MSCRMCallerID, имя пользователя (d994d6ff-5531-e711-9422-00155dc0d345), а поле CreatedOnBehalf пусто.

Что мы делаем неправильно?

Как мы получаем эту олицетворение, работающую от нашего сервиса?

EDIT + Дополнительная информация

Обратите внимание, что я считаю, что я включил всю соответствующую информацию, но если у меня ее нет, сообщите мне, какой другой ввод я должен предоставить по этой проблеме.

Что я пробовал?

  • изменил порядок заголовков
  • играет со случаем заголовков
  • гарантировал, что руководство правильное для пользователя для олицетворения
  • гарантировал, что у пользователя есть как роль делегирования, так и роль администратора sys (хотя это не имеет значения, поскольку это работает при выполнении запроса непосредственно с оконечной точкой crm odata, а не с конечной точкой, предоставляемой нашей службой
  • попытались выполнить запрос как по https, так и по http
  • трассировка скрипача, как показано ниже

Обратите внимание, что эта трассировка скрипта - это трассировка с запросом Почтальон → Микросервис. Он не показывает связь с микросервисом 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 предположил, что мы используем службу организации для аутентификации, - это вариант, учитывая, что мы выполняем действия против веб-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.");
                }
4b9b3361

Ответ 1

Когда вы выполняете запрос Postman для CRM, его прямой вызов и CRM обрабатывают его ожидаемым образом.

Но в Postman → Microservice → CRM заголовок теряется между Microservice и CRM.

В вашем Microservice вам необходимо вручную обрабатывать заголовок для вызова CRM SDK.

HttpWebRequest myHttpWebRequest1= (HttpWebRequest)WebRequest.Create(uri);
myHttpWebRequest1.Headers.Add("MSCRMCallerID", "D994D6FF-5531-E711-9422-00155DC0D345");

Или HTTP Header Forwarding (Извините, что не удалось найти его для Azure/С#)

введите описание изображения здесь

Update:

Предположим, что вы следуете этим образцам MSDN, чтобы выполнить свой CRM-ави-вызов в С# microservice. Я включил наш заголовок в необходимости - 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);
   }
}

Ответ 2

Есть несколько вещей, которые вы должны заботиться при олицетворении

1. Чтобы олицетворять пользователя, установите свойство CallerId на экземпляр   OrganizationServiceProxy перед вызовом веб-методов служб.

2. Пользователь (имитатор) должен иметь привилегию ActOnBehalfOf или быть членом группы PrivUserGroup в Active Directory

Пример кода

 SystemUser user = null;
 user = new SystemUser(systemUser);
 OrganizationServiceProxy service = CrmService.Proxy;
 service.CallerID = user.Id;

Поскольку ваш код недоступен, убедитесь, что все указанные выше поля установлены правильно

Для детального понимания используйте ссылку https://crmbusiness.wordpress.com/2015/07/21/crm-2015-understanding-impersonation-in-plugins-and-knowing-when-to-use-it/