2013-06-10 2 views
2

У меня есть веб-api, чтобы разрешить доступ к перекрестному домену с помощью Basic Authentication. Когда я делаю запрос GET для кросс-домена API, он отлично работает, и я получаю токен в заголовке «Авторизация» в своем обработчике сообщений. Но при запуске запроса POST для перекрестного домена я не получаю заголовок «Авторизация», поэтому не удается проверить запрос.Веб-Api Cross Domain Основная проверка подлинности

Любая помощь будет высоко оценена.

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

using System; 
    using System.Linq; 
    using System.Net; 
    using System.Net.Http; 
    using System.Threading; 
    using System.Threading.Tasks; 

    namespace MyWebApi.Handlers 
    { 
     public class XHttpMethodOverrideDelegatingHandler : DelegatingHandler 
     { 
      static readonly string[] HttpOverrideMethods = { "PUT", "DELETE" }; 
      static readonly string[] AccessControlAllowMethods = { "POST", "PUT", "DELETE" }; 
      private const string HttpMethodOverrideHeader = "X-HTTP-Method-Override"; 
      private const string OriginHeader = "ORIGIN"; 
      private const string AccessControlAllowOriginHeader = "Access-Control-Allow-Origin"; 
      private const string AccessControlAllowMethodsHeader = "Access-Control-Allow-Methods"; 
      private const string AccessControlAllowHeadersHeader = "Access-Control-Allow-Headers"; 

      protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
      { 


       var authHeader = request.Headers.Authorization; 

       if (authHeader == null || authHeader.Scheme != "Basic" || string.IsNullOrWhiteSpace(authHeader.Parameter)) 
       { 
        return CreateUnauthorizedResponse(); 
       } 

       if (request.Method == HttpMethod.Post && request.Headers.Contains(HttpMethodOverrideHeader)) 
       { 
        var httpMethod = request.Headers.GetValues(HttpMethodOverrideHeader).FirstOrDefault(); 
        if (HttpOverrideMethods.Contains(httpMethod, StringComparer.InvariantCultureIgnoreCase)) 
         request.Method = new HttpMethod(httpMethod); 
       } 

       var httpResponseMessage = base.SendAsync(request, cancellationToken); 

       if (request.Method == HttpMethod.Options && request.Headers.Contains(OriginHeader)) 
       { 
        httpResponseMessage.Result.Headers.Add(AccessControlAllowOriginHeader, request.Headers.GetValues(OriginHeader).FirstOrDefault()); 
        httpResponseMessage.Result.Headers.Add(AccessControlAllowMethodsHeader, String.Join(", ", AccessControlAllowMethods)); 
        httpResponseMessage.Result.Headers.Add(AccessControlAllowHeadersHeader, HttpMethodOverrideHeader); 
        httpResponseMessage.Result.StatusCode = HttpStatusCode.OK; 
       } 
       //No mater what the HttpMethod (POST, PUT, DELETE), if a Origin Header exists, we need to take care of it 
       else if (request.Headers.Contains(OriginHeader)) 
       { 
        httpResponseMessage.Result.Headers.Add(AccessControlAllowOriginHeader, request.Headers.GetValues(OriginHeader).FirstOrDefault()); 
       } 

       return httpResponseMessage; 
      } 

      private Task<HttpResponseMessage> CreateUnauthorizedResponse() 
      { 
       var response = new HttpResponseMessage(HttpStatusCode.Unauthorized); 
       response.Headers.Add("WWW-Authenticate", "Basic"); 

       var taskCompletionSource = new TaskCompletionSource<HttpResponseMessage>(); 
       taskCompletionSource.SetResult(response); 
       return taskCompletionSource.Task; 
      } 
     } 
    } 

И я зарегистрировал выше обработчик в Application_Start следующим образом:

namespace MyWebApi 
    { 
     public class Global : System.Web.HttpApplication 
     { 
      protected void Application_Start(object sender, EventArgs e) 
      { 
       RouteTable.Routes.MapHttpRoute(
        name: "DefaultApi", 
        routeTemplate: "api/{controller}/{action}/{id}", 
        defaults: new {id = RouteParameter.Optional}); 
       GlobalConfiguration.Configuration.MessageHandlers.Add(new XHttpMethodOverrideDelegatingHandler()); 
       GlobalConfiguration.Configuration.Formatters.Insert(0, new JsonpMediaTypeFormatter()); 
      } 
     } 
    } 

На стороне клиента на другой проект домена, я пытаюсь добавить новую запись, используя следующий код.

 AddUser { 

       var jsonData = { 
        "FirstName":"My First Name", 
        "LastName": "My Last Name", 
        "Email": "[email protected]", 
        "Password": "MyPa$$word" 
       }; 

       $.ajax({ 
        type: "POST", 
        dataType: 'json', 
        url: "http://localhost:4655/api/user/signup", 
        beforeSend: function (xhr) { xhr.setRequestHeader("Authorization", "Basic xxxxxxxxxxxxxx"); }, 
        accept: "application/json", 
        data: JSON.stringify(jsonData), 
        success: function (data) { 
         alert("success"); 
        }, 
        failure: function (errorMsg) { 
         alert(errorMsg); 

        }, 
        error: function (onErrorMsg) { 
         alert(onErrorMsg.statusText); 
        }, 
        statusCode: function (test) { 
         alert("status"); 
        } 
       }); 
      }); 

И ниже приведен код для моего пользовательского контроллера.

namespace MyWebApi.Controllers 
    { 
     public class UserController : ApiController 
     { 

      [HttpPost] 
      [ActionName("Adduser")] 
      public int Post(UserModel source) 
      { 
        if (source == null) 
        { 
         throw new ArgumentNullException("source"); 
        } 
        Db.Users.Add(source); 
        Db.SaveChanges(); 

        return source.UserId; 
      }     
     } 
    } 

Заранее благодарен!

+0

Я тоже пытаюсь подключить до службы Web API REST, чтобы базовое разрешение и обеспечить возможность CORS запросов (GET и POST). Основываясь на приведенной ниже статье, я задаюсь вопросом, считается ли это лучшей практикой использовать этот код в производстве. Вам удалось заставить это работать? http://blog.bittercoder.com/2012/09/09/cors-and-webapi/ – likestoski

+0

К сожалению, нет. Я не нашел способ заставить его работать. И из-за сложностей и зависимостей браузера я отказался от этого, чтобы использовать CORS API WEB. – tahir76

ответ

0

Я обнаружил, что если я включаю базовые учетные данные для аутентификации в свой запрос XHR для кросс-домена (POST), браузер (IE, Chrome, Firefox) отклоняет запрос до его получения на моем сервере - и это правда даже если я укажу withCredentials:true в своем первоначальном запросе $ .ajax(). Я предполагаю, что в спецификации CORS есть что-то, что требует этого. Но я думаю, что короткий ответ заключается в том, что вы не можете указывать базовый auth в запросах CORS.

Конечно, вы можете обойти это другими способами, передавая идентификаторы пользователей и пароли как часть самого URL-адреса, поэтому я не совсем понимаю, что, по их мнению, они набирают, ограничивая его, но, по-видимому, они имеют некоторая причина.

+0

Вы поняли это, я думаю, это может быть с сервером, который не понимает VerFlight OPTIONS Verb. Сделайте запрос с помощью OPTIONS в качестве глагола, и сервер выбрасывает 404, что и происходит в моем приложении. Я не думаю, что это проблема с браузером. – TYRONEMICHAEL

+0

@TyroneMichael - Здесь еще немало темной магии, поэтому я не претендую на то, чтобы разобраться в чем-то окончательно :-). Но я смог правильно понять сервер и правильно ответить на глагол prefllight OPTIONS, поэтому я не думаю, что проблема была серверной. Прошло несколько недель, но, как я помню из моего тестирования, единственным объяснением поведения, которое я наблюдал, было то, что браузер блокировал мои запросы XHR с помощью базового auth. Я хотел бы ошибаться - это сценарий, который я хотел бы работать. –

+0

YA экспериментировал весь день. Установлены ночные сборки Web-Api и, похоже, ушли по касательной. Пытался пойти по этому маршруту [ссылка] (http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api).Однако все равно получите 404, когда браузер пытается выполнить предполетный запрос, используя базовый auth. Если я не настрою заголовок Auth, все работает нормально, и мои точки останова попадают. – TYRONEMICHAEL

0

Вам необходимо украсить ваш контроллер с помощью [HttpOptions], а также [HttpPost]. В противном случае, когда он делает запрос, используя глагол OPTIONS, он будет бросать 404. Таким образом, ваш контроллер будет

 [HttpPost] 
     [HttpOptions] 
     [ActionName("Adduser")] 
     public int Post(UserModel source) 
     { 
       if (source == null) 
       { 
        throw new ArgumentNullException("source"); 
       } 
       Db.Users.Add(source); 
       Db.SaveChanges(); 

       return source.UserId; 
     } 
+0

Я дам этот снимок - спасибо ! –