2017-02-14 6 views
1

Я пытаюсь получить доступ к WebAPI, который использует ValidateAntiForgeryToken. Мой WebAPI Метод заключается в следующем (простой один), который находится внутри контроллера пользователя (только для тестирования):Доступ к WebAPI с AntiForgeryToken в Aspnet 5.0 на Xamarin

[HttpPost] 
[ValidateAntiForgeryToken] 
public ActionResult Test(String field) 
{ 
    String result = String.Empty; 
    if (ModelState.IsValid) 
    { 
     HtmlSanitizer sanitizer = new HtmlSanitizer(); 

     try 
     { 
      result = sanitizer.Sanitize(field); 
     } 
     catch (Exception ex) 
     { 
      result = ex.Message; 
      throw; 
     } 
    } 
    return Json(result); 
} 

С Ajax, я могу получить доступ к нему с легкостью:

$.ajax({ 
    url: '/User/Test', 
    type: "POST", 
    contentType: "application/x-www-form-urlencoded", 

    data: { 

     field: self.textField(), 
     __RequestVerificationToken: $("input[name='__RequestVerificationToken']").val(), 
    }, 
    success: function(e) { 
     self.textField(e) 
     self.divField(e); 
    }, 
    error: function(e) { 
     console.log(e.error()); 
    }, 
}); 

Но, до сих пор я не могу получить доступ к этому webapi с помощью httpclient на xamarin. Это мой код:

private async void DoTestWebApi() 
{ 
    try 
    { 
     HttpClient clientPage = new HttpClient() 
     { 
      BaseAddress = new Uri("https://localhost:44356/user") 
     }; 

     var pageWithToken = await clientPage.GetAsync(clientPage.BaseAddress); 

     String verificationToken = GetVerificationToken(await pageWithToken.Content.ReadAsStringAsync()); 

     HttpClient client = new HttpClient() 
     { 
      BaseAddress = new Uri("https://localhost:44356/user/test/") 
     }; 

     HttpRequestMessage message = new HttpRequestMessage() 
     { 
      RequestUri = new Uri("https://localhost:44356/user/test/"), 
      Method = HttpMethod.Post 
     }; 

     message.Headers.Add("__RequestVerificationToken", verificationToken); 

     String field = "teste"; 

     //StringContent content = new StringContent("field=test", Encoding.UTF8, "application/x-www-form-urlencoded"); 
     StringContent content = new StringContent("__RequestVerificationToken=" + verificationToken + ",field=test", Encoding.UTF8, "application/x-www-form-urlencoded"); 

     // this doesn't work 
     //client.DefaultRequestHeaders.Add("__RequestVerificationToken", verificationToken); 
     var response2 = await client.SendAsync(message); 

     if (response2.IsSuccessStatusCode) 
     { 
      var t = response2.Content.ReadAsStringAsync(); 

      if (true) 
      { 
       // just to check if t has value 
      } 
     } 

    } 
    catch (Exception ex) 
    { 
     Console.WriteLine(ex.Message); 
     throw; 
    } 

} 

Честно говоря, я не знаю, что еще я мог сделать, чтобы передать свой анти маркера подделки в сообщении. Он отлично работает в ajax, я передаю его внутри содержимого данных, но в xamarin он не работает. Весь код выполняется внутри одного и того же локального хоста. Если я удалю [ValidateAntiForgeryToken], он будет работать.

Что мне не хватает?

Edit:

Итак, теперь я шлю с печеньем, но опять-таки не ударять метод. Это мое обновление:

HttpClient clientPage = new HttpClient() 
{ 
    BaseAddress = new Uri("https://localhost:44356/user") 
}; 

var pageWithToken = await clientPage.GetAsync(clientPage.BaseAddress); 

String verificationToken = GetVerificationToken(await pageWithToken.Content.ReadAsStringAsync()); 

List<KeyValuePair<String, String>> cookiesInfo = new List<KeyValuePair<String, String>>(); 

foreach (var item in pageWithToken.Headers) 
{ 
    cookiesInfo.Add(new KeyValuePair<String, String>(item.Key, item.Value.ToString())); 
} 

cookiesInfo.Add(new KeyValuePair<string, string>("field", "value")); 
cookiesInfo.Add(new KeyValuePair<string, string>("__RequestVerificationToken", verificationToken)); 

CookieContainer cookieContainer = new CookieContainer(); 

using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer }) 
{ 
    using (var client = new HttpClient(handler) { BaseAddress = new Uri("https://localhost:44356/user") }) 
    { 
     var content = new FormUrlEncodedContent(cookiesInfo); 

     cookieContainer.Add(client.BaseAddress, new Cookie("__RequestVerificationToken", verificationToken)); 

     foreach (var item in cookiesInfo) 
     { 
      cookieContainer.Add(client.BaseAddress, new Cookie(item.Key, item.Value)); 
     } 

     var result = client.PostAsync(new Uri("https://localhost:44356/user/test"), content).Result; 

     result.EnsureSuccessStatusCode(); 
    } 

}; 

Это сводит меня с ума ... Хорошо тест в локальный, но вскоре это приложение будет в лазури, и это является предварительным условием ...


Edit: GetVerificationToken Метод:

private string GetVerificationToken(String verificationToken) 
    { 
     if (verificationToken != null && verificationToken.Length > 0) 
     { 
      verificationToken = verificationToken.Substring(verificationToken.IndexOf("__RequestVerificationToken")); 
      verificationToken = verificationToken.Substring(verificationToken.IndexOf("value=\"") + 7); 
      verificationToken = verificationToken.Substring(0, verificationToken.IndexOf("\"")); 
     } 

     return verificationToken; 
    } 
+0

Вы можете захватить запросы, отправленные на ваш API с помощью такого инструмента, как [Скрипач] (http://www.telerik.com/fiddler) и сравните ajax с HttpClient. Это может дать вам некоторые подсказки относительно того, каковы различия. –

+0

'localhost'? localhost, используемый в вашем телефоне/эмуляторе, будет телефоном/эмулятором, а не вашим компьютером. Используйте имя хоста/IP-адрес хоста, на котором запущено приложение aspnet/iis, которое разрешимо с телефона/эмулятора, попробуйте использовать браузер устройства, чтобы открыть этот URL-адрес в качестве теста ... – SushiHangover

+0

да, localhost. потому что все приложения выполняются на одном компьютере. И это работает, это не проблема (если я удалю ValidateAntiForgeryToken, нормально работает) –

ответ

2

ValidateAntiForgeryToken также ожидает печенье с __RequestVerificationToken и значение при условии. Это делается для того, чтобы одна публикация на контроллер была той, кто просматривал форму.

+0

Я обновил свой вопрос, но, похоже, что cookie - это не только проблема. Я отправляю сейчас файлы cookie. Я пытаюсь использовать инструмент Advanced Rest Client (Chrome), и даже если я устанавливаю файлы cookie в этом инструменте, он не работает. –

1

Благодаря подсказке @Zroq, я наконец сделал это. Печенье действительно пропало. Это окончательный вариант моего метода, который передает данные WebAPI с AntiForgeryToken в ASP.Net MVC 5.0:

private async void DoTestWebApi() 
    { 
     try 
     { 
      CookieContainer cookieContainer = new CookieContainer(); 

      HttpClientHandler handlerhttps = new HttpClientHandler 
      { 
       UseCookies = true, 
       UseDefaultCredentials = true, 
       CookieContainer = cookieContainer 
      }; 

      HttpClient clientPage = new HttpClient(handlerhttps) 
      { 
       BaseAddress = new Uri("https://localhost:44356/user") 
      }; 

      var pageWithToken = await clientPage.GetAsync(clientPage.BaseAddress); 

      String verificationToken = GetVerificationToken(await pageWithToken.Content.ReadAsStringAsync()); 

      var cookies = cookieContainer.GetCookies(new Uri("https://localhost:44356/user")); 

      using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer, UseDefaultCredentials = true, UseCookies = true }) 
      { 
       using (var client = new HttpClient(handler) { BaseAddress = new Uri("https://localhost:44356/user/test") }) 
       { 
        var contentToSend = new FormUrlEncodedContent(new[] 
        { 
         new KeyValuePair<string, string>("field", "value"), 
         new KeyValuePair<string, string>("__RequestVerificationToken", verificationToken), 
        }); 

        var response = client.PostAsync(client.BaseAddress, contentToSend).Result; 
       } 
      }; 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex.Message); 
     } 
    } 

Еще раз спасибо @Zroq.

+0

Привет. Где GetVerificationToken() метод? –

+0

Есть ли способ отправить объект вместо строки? Я не хочу использовать Json.Deserialized на стороне сервера. потому что я хочу использовать ModelState. –

+0

Я сейчас не на своем компьютере, но AFAIK вы можете отправить как StringContent, который вы отправляете на свой сервер объекты JSON: http://stackoverflow.com/questions/11145053/cant-find-how-to-use -httpcontent и http://stackoverflow.com/questions/18971510/how-do-i-set-up-httpcontent-for-my-httpclient-postasync-second-parameter Этот метод ожидает только объект JSON или String, насколько я помню, вы не можете отправить в него свой пользовательский объект. –

0

Для всех, кто хочет() тело GetVerificationToken:

private string GetVerification(string responseBody) 
{ 
    var data = QueryHelpers.ParseQuery(queryString: responseBody); 
    string firstValue = data[key: "<input name"]; 
    var cutedValue = firstValue.Remove(startIndex: 0, count: 50); 
    var result = cutedValue.Split('"')[0]; 
    return result; 
} 
+0

Я добавил метод GetVerificationToken на этот вопрос. –

+0

Извините, я этого не видел. –