2013-09-24 58 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