2013-09-24 57 views
2

我一直在通過一個簡單的API示例,ServiceStack Hello World示例的帶有認證的修改版本。概念證明的目標是創建一個RESTful API,其中包含需要完全通過來自多個不同Web項目的Ajax訪問身份驗證的服務。使用Ajax訪問ServiceStack認證服務

我已經閱讀了wiki,並且實現了認證和授權,並實現了CORS(許多結果[抱歉,沒有足夠的信譽指向相關鏈接])。此時,我的Hello服務可以使用自定義身份驗證機制進行身份驗證,該身份驗證機制覆蓋CredentialsAuthProvider和自定義用戶會話對象。我創建或借用了一個簡單的測試應用程序(一個完全獨立的項目來模擬我們的需求),並且可以進行身份​​驗證,然後調用Hello服務,傳遞一個名稱,並通過一個單一接收「Hello Fred」響應瀏覽器會話。也就是說,我可以調用url中的/ auth/credentials路徑,傳遞用戶名和id,並接收適當的響應。然後,我可以將URL更新爲/ hello/fred並接收有效的響應。

我理解的細節是如何實現所有ajax調用的身份驗證。我在下面的初始登錄,工作正常。無論我做什麼,嘗試通過ajax調用已驗證的服務,我都會收到一個OPTIONS 404錯誤或Not Found錯誤,或者Access http // localhost:12345(僞鏈接),Access-Control-Allow -Origin等

我需要去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 : "")); 
     } 
    }); 
} 

編輯:

基於響應和斯特凡提供的鏈接,我做了一些改動:

我的配置(注:我使用定製認證和會話對象,並且所有工作都正常)。

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); 
} 

我簡單的Hello服務

[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 }; 
    } 
} 

進行登錄通話,以上後,我的後續調用Hello服務正在產生一個401錯誤,這是進步,雖然不是我需要的人。 (該Jquery.support.cors = true在我的腳本文件中設置。)

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 以下Stefan的建議,包括許多其他的鏈接,我終於能夠得到這個工作。除了Stefan的代碼,我不得不做出一個額外的修飾:

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

下一個挑戰:更新喬納斯埃裏克森的CustomAuthenticateAttibute代碼(這顯然是利用ServiceStack舊版本的一對夫婦的功能都沒有可用時間更長

再次感謝STEFAN!

+0

我很困惑。你能更清楚地陳述你的問題嗎? – zanbri

+0

如果沒有身份驗證,你可以在AJAX中做一個簡單的調用來檢查CORS是否像這樣[answer](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; 
     } 

登錄第

  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); 
       } 
      }); 
     } 

這些問題herehere是有益的。

另外這個answer for CredentialsAuthProvider,以防我們可以使用cookie和sessions

+0

成功登錄後,Hello服務調用的結果相同:401(未授權) – ithank

+0

也許您的問題不在CORS中,而是在您的授權過程中。你有沒有讀過[爲ServiceStack.net定製IAuthProvider - 分步驟](http://enehana.nohea.com/general/customizing-iauthprovider-for-servicestack-net-step-by-step/) – stefan2410

+0

是的,我有。這基本上是我的配置。認證過程很好。如上所述,通過RESTConsole,我可以成功登錄,然後將呼叫更改爲/ hello並且工作正常。使用上面指出的我的ajax調用,登錄工作正常,隨後的ajax調用/ hello由於缺乏身份驗證而失敗。我必須錯過關於如何處理/使用返回的會話ID和/或ss-id/ss-pid cookie的事情? – ithank