2013-09-24 4 views
2

Я работал с простым примером API, с модифицированной версией примера ServiceStack Hello World с проверкой подлинности. Целью доказательства концепции является создание RESTful API, который содержит службы, требующие аутентификации, доступные полностью через Ajax из нескольких различных веб-проектов.Доступ к службе проверки подлинности ServiceStack с использованием Ajax

Я прочитал вики и реализовал, аутентификацию и авторизацию и внедрение CORS (многие, результаты [извините, недостаточно, чтобы указать на соответствующую ссылку]). На этом этапе моя служба Hello может пройти аутентификацию с использованием настраиваемого механизма проверки подлинности, который перегружает CredentialsAuthProvider и пользовательский объект сеанса пользователя. Я создал или заимствовал, скорее, простое тестовое приложение (полностью отдельный проект для моделирования наших потребностей) и может пройти аутентификацию, а затем позвонить в службу Hello, передать имя и получить ответ «Hello Fred» через один сеанс браузера. То есть я могу вызвать путь/auth/credentials в URL-адресе, передать имя пользователя и идентификатор и получить правильный ответ. Затем я могу обновить URL-адрес/hello/fred и получить действительный ответ.

Мое нарушение в понимании заключается в том, как реализовать аутентификацию для всех вызовов ajax. Мой первоначальный логин, ниже, отлично работает. Независимо от того, что я делаю, моя попытка вызвать аутентифицированную службу через ajax, я либо получаю ошибку OPTIONS 404, либо ошибку Not Found, либо Origin http // localhost: 12345 (псевдосвязь) не разрешена Access-Control-Allow -Оригин и т. Д.

Нужно ли мне ехать this route?

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

function InvokeLogin() { 
    var Basic = new Object(); 
    Basic.UserName = "MyUser"; 
    Basic.password = "MyPass"; 

    $.ajax({ 
     type: "POST", 
     contentType: "application/json; charset=utf-8", 
     dataType: "json", 
     data: JSON.stringify(Basic), 
     url: "http://localhost:58795/auth/credentials", 
     success: function (data, textStatus, jqXHR) { 
       alert('Authenticated! Now you can run Hello Service.'); 
      }, 
     error: function(xhr, textStatus, errorThrown) { 
      var data = $.parseJSON(xhr.responseText); 
      if (data === null) 
       alert(textStatus + " HttpCode:" + xhr.status); 
      else 
       alert("ERROR: " + data.ResponseStatus.Message + (data.ResponseStatus.StackTrace ? " \r\n Stack:" + data.ResponseStatus.StackTrace : "")); 
     } 
    }); 
} 

EDIT:

На основе ответов и связи, предоставленной Стефан, я сделал несколько изменений:

My Config (Примечание: Я использую пользовательская аутентификация и объект сеанса, и все это работает правильно.)

public override void Configure(Funq.Container container) 
{ 
    Plugins.Add(new AuthFeature(() => new CustomUserSession(), 
       new IAuthProvider[] { 
       new CustomCredentialsAuthProvider(), 
        })); 

    base.SetConfig(new EndpointHostConfig 
    { 
     GlobalResponseHeaders = { 
      { "Access-Control-Allow-Origin", "*" }, 
      { "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" }, 
      { "Access-Control-Allow-Headers", "Content-Type, Authorization" }, 
     }, 
     DefaultContentType = "application/json" 
    }); 

    Plugins.Add(new CorsFeature()); 
    this.RequestFilters.Add((httpReq, httpRes, requestDto) => 
    { 
     //Handles Request and closes Responses after emitting global HTTP Headers 
     if (httpReq.HttpMethod == "OPTIONS") 
      httpRes.EndRequest(); // extension method 
    }); 

    Routes 
     .Add<Hello>("/Hello", "GET, OPTIONS"); 


    container.Register<ICacheClient>(new MemoryCacheClient()); 
    var userRep = new InMemoryAuthRepository(); 
    container.Register<IUserAuthRepository>(userRep); 
} 

My Simple Hello Service

[EnableCors] 
public class HelloService : IService 
{ 
    [Authenticate] 
    public object GET(Hello request) 
    { 
     Looks strange when the name is null so we replace with a generic name. 
     var name = request.Name ?? "John Doe"; 
     return new HelloResponse { Result = "Hello, " + name }; 
    } 
} 

После принятия вызова входа в систему, выше, мой последующий вызов службы Привет теперь получают сообщение об ошибке 401, который прогресс, хотя и не там, где мне нужно быть. (The Jquery.support.cors = истина устанавливается в моем файле сценария.)

function helloService() { 
    $.ajax({ 
     type: "GET", 
     contentType: "application/json", 
     dataType: "json", 
     url: "http://localhost:58795/hello", 
     success: function (data, textStatus, jqXHR) { 
      alert(data.Result); 
     }, 
     error: function (xhr, textStatus, errorThrown) { 
      var data = $.parseJSON(xhr.responseText); 
      if (data === null) 
       alert(textStatus + " HttpCode:" + xhr.status); 
      else 
       alert("ERROR: " + data.ResponseStatus.Message + 
        (data.ResponseStatus.StackTrace ? " \r\n Stack:" + data.ResponseStatus.StackTrace : "")); 
     } 
    }); 
} 

Опять же, это работает в RESTConsole, если я сначала сделать вызов/AUTH/полномочия должным образом, а затем следить за этим с вызвать/привет.

FINAL EDIT После посоветуйте Стефана, ниже, в том числе и многие другие ссылки, я, наконец, смог получить эту работу. В дополнение к коду Стефана, я должен был сделать еще одну модификацию:

Plugins.Add(new CorsFeature(allowedHeaders: "Content-Type, Authorization")); 

На следующую задачу: Обновление CustomAuthenticateAttibute код Йонаса Эрикссона (который не кажется, использует старую версию ServiceStack как пару функций нет дольше.

СПАСИБО СНОВА СТЕФАН !!

+0

Я в замешательстве. Можете ли вы сформулировать свой вопрос немного более четко? – zanbri

+0

Без аутентификации вы можете сделать простой вызов в AJAX, чтобы проверить, работает ли CORS в этом [ответе] (http://stackoverflow.com/questions/18923930/sending-data-to-servicestack-restful-service-getting -access-is-denied/18927067 # 18927067)? Вы можете проверить свой код в AppHost? В javascript вы писали jQuery.support.cors = true; – stefan2410

+0

Спасибо за понимание Стефана. Похоже, проблемы этого человека были очень похожи на то, что я испытываю. Я рассмотрю этот пример, посмотрю, каковы мои результаты. И обновите этот пост. Еще раз спасибо. – ithank

ответ

2

этот код работает для меня, на основе документации Wiki Custom authentication and authorization

Кодекс основан также в блоге от сообщества ресурсов CORS BasicAuth on ServiceStack with custom authentication

для базовой аутентификации, пользовательского поставщика

public class myAuthProvider : BasicAuthProvider 
    { 
      public myAuthProvider() : base() { } 

     public override bool TryAuthenticate(IServiceBase authService, string userName, string password) 
    { 
     //Add here your custom auth logic (database calls etc) 
     //Return true if credentials are valid, otherwise false 
     if (userName == "admin" && password == "test") 
         return true; 
     else 
       return false; 

    } 

    public override void OnAuthenticated(IServiceBase authService, IAuthSession session, IOAuthTokens tokens, Dictionary<string, string> authInfo) 
    { 
     //Fill the IAuthSession with data which you want to retrieve in the app 
     // the base AuthUserSession properties e.g 
     session.FirstName = "It's me"; 
     //... 
     // derived CustomUserSession properties e.g 
     if(session is CustomUserSession) 
     ((CustomUserSession) session).MyData = "It's me"; 
     //... 
     //Important: You need to save the session! 
     authService.SaveSession(session, SessionExpiry); 
    } 
} 

public class CustomUserSession : AuthUserSession 
{ 

    public string MyData { get; set; } 
} 

В AppHost

 using System.Web; 
    using ServiceStack;  // v.3.9.60 httpExtensions methods, before in ServiceStack.WebHost.Endpoints.Extensions; 

    using .... 

AppHost.Configure

 public override void Configure(Container container) 
     { 
      SetConfig(new ServiceStack.WebHost.Endpoints.EndpointHostConfig 
      { 
       DefaultContentType = ContentType.Json 
       .. 
       // remove GlobalResponseHeaders because CordFeature adds the CORS headers to Config.GlobalResponseHeaders 

      }); 
     Plugins.Add(new CorsFeature(allowedHeaders: "Content-Type, Authorization")); //Registers global CORS Headers 
     this.RequestFilters.Add((httpReq, httpRes, requestDto) => 
     { 
      if (httpReq.HttpMethod == "OPTIONS") 
        httpRes.EndRequestWithNoContent(); // v 3.9.60 httpExtensions method before httpRes.EndServiceStackRequest(); 

     }); 

      //Register all Authentication methods you want to enable for this web app. 
      Plugins.Add(new AuthFeature(() => new CustomUserSession(), // OR the AuthUserSession 
       new IAuthProvider[] { 
       new myAuthProvider(), 
       }) { HtmlRedirect = null }); // Redirect on fail 

HtmlRedirect answer

   Routes.Add<TestRequest>("/TestAPI/{Id}", "POST,GET, OPTIONS"); 
     .... 
     } 

В службе

  [Authenticate] 
      public class TestAPI : Service 
      {  
       ... 
      } 

В JavaScript

 jQuery.support.cors = true; 

     function make_base_auth(user, password) { 
      var tok = user + ':' + password; 
      var hash = btoa(tok); 
      return "Basic " + hash; 
     } 

Logi п первый

  function Authenticate() { 

       $.ajax({ 
       type: 'Post', 
       contentType: 'application/json', 
       url: serverIP + 'Auth', 
       cache: false, 
       async: false, 
       data: {}, 
       dataType: "json", 
       beforeSend: function (xhr) { 
        xhr.setRequestHeader("Authorization", make_base_auth(username, password)); 
       }, 
       success: function (response, status, xhr) { 
        localStorage.sessionId = data.SessionId; 
        var UserName = response.userName; 
       }, 
       error: function (xhr, err) { 
        alert(err); 
       } 
      }); 
     } 

и просить

  function DoTest() { 
       var TestRequest = new Object(); 
       TestRequest.name = "Harry Potter";    
       TestRequest.Id = 33; 
      var username = "admin"; 
      var password = "test"; 

      $.ajax({ 
       type: 'Post', 
       contentType: 'application/json', 
       cache: false, 
       async: false, 
       url: serverIP + '/TestAPI/'+ TestRequest.Id, 
       data: JSON.stringify(TestRequest), 
       dataType: "json",     
       beforeSend: function (xhr) {      
       xhr.setRequestHeader("Session-Id", localStorage.sessionId); 
       }, 
      success: function (response, status, xhr) { 
        var s= response.message;  
       }, 
       error: function (xhr, err) { 
        alert(xhr.statusText); 
       } 
      }); 
     } 

эти вопросы here и here полезны.

Также это answer для CredentialsAuthProvider, если мы сможем использовать файлы cookie и sessions.

+0

Тот же результат в сервисном вызове Hello после успешного входа в систему: 401 (неавторизованный) – ithank

+0

Возможно, ваша проблема связана не с CORS, а с вашим процессом авторизации. Вы читали это [Настройка IAuthProvider для ServiceStack.net - шаг за шагом] (http://enehana.nohea.com/general/customizing-iauthprovider-for-servicestack-net-step-by-step/) – stefan2410

+0

Да, я иметь. В основном это моя конфигурация. Процесс аутентификации прекрасен. Как уже упоминалось, через RESTConsole я могу войти в систему успешно, а затем изменить вызов на/hello, и он отлично работает. Используя мои вызовы ajax, указанные выше, логин работает нормально, последующий вызов ajax/hello не работает из-за отсутствия аутентификации. Я должен что-то пропустить, как обрабатывать/использовать возвращаемый идентификатор сеанса и/или файлы cookie ss-id/ss-pid ??? – ithank

Смежные вопросы