2013-08-21 32 views
5

Tôi đang gặp sự cố khi giải quyết kiến ​​trúc của ứng dụng ASP MVC mà máy chủ lưu trữ các trang html và dịch vụ web thông qua ServiceStack.API ServiceStack và Xác thực ASP MVC theo hai cách

Ứng dụng hoạt động trong url cơ sở, ví dụ: "http://myapplication.com" và SS tồn tại trong "http://myapplication.com/api" vì đó là cách dễ nhất để định cấu hình cả hai.

Nói chung mọi thứ hoạt động tốt, nhưng khi tôi đạt được một phần của ủy quyền và xác thực, là nơi tôi bị kẹt.

Đối với một, tôi cần ứng dụng xử lý cookie như ASP thường thực hiện FormsAuthentication và người dùng sẽ xem qua màn hình đăng nhập và có thể sử dụng các hành động và bộ điều khiển khi thuộc tính "Ủy quyền" được sử dụng. Đây là điển hình của ASP, vì vậy tôi không có vấn đề với nó, chẳng hạn như "http://myapplication.com/PurchaseOrders".

Mặt khác, các ứng dụng khách của tôi sẽ sử dụng api dịch vụ web của tôi từ javascript. Các dịch vụ web đó cũng sẽ được gắn thẻ trong một số trường hợp với thuộc tính "Authenticate" của ServiceStack. Ví dụ: "http://myapplication.com/api/purchaseorders/25" sẽ phải xác thực nếu người dùng có thể xem đơn đặt hàng cụ thể đó, nếu không gửi 401 Không được ủy quyền để javascript có thể xử lý các trường hợp đó và hiển thị thông báo lỗi.

Cuối cùng nhưng không kém phần quan trọng, một nhóm người dùng khác sẽ sử dụng API của tôi bằng mã thông báo, sử dụng bất kỳ ứng dụng bên ngoài nào (có thể là Java hoặc .NET). Vì vậy, tôi cần phải giải quyết hai loại xác thực, một loại sử dụng tên người dùng và mật khẩu, một bằng mã thông báo và làm cho chúng tồn tại lâu hơn, khi chúng được xác thực lần đầu tiên, các cuộc gọi tiếp theo sẽ nhanh hơn để giải quyết từ API.

Đây là mã mà tôi có cho đến nay, tôi đã đặt nó rất đơn giản để làm rõ ví dụ.

[HttpPost] 
    public ActionResult Logon(LogOnModel model, string returnUrl) 
    { 
     if (ModelState.IsValid) 
     { 
      JsonServiceClient client = new JsonServiceClient("http://myapplication.com/api/"); 
      var authRequest = new Auth { provider = CredentialsAuthProvider.Name, UserName = model.UserName, Password = model.Password, RememberMe = model.RememberMe }; 
      try 
      { 

       var loginResponse = client.Send(authRequest); 

       FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(loginResponse.UserName, false, 60); 
       var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket)); 
       Response.Cookies.Add(cookie); 

       if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\")) 
       { 
        return Redirect(returnUrl); 
       } 
       else 
       { 
        return RedirectToAction("Index", "Test"); 
       } 

      } 
      catch (Exception) 
      { 
       ModelState.AddModelError("", "Invalid username or password"); 
      } 
     } 

     return View(); 
    } 

Đối với các nhà cung cấp chứng thực Tôi đang sử dụng lớp

public class MyCredentialsAuthProvider : CredentialsAuthProvider 
{ 
    public MyCredentialsAuthProvider(AppSettings appSettings) 
     : base(appSettings) 
    { 

    } 

    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 == "testuser" && password == "nevermind") 
     { 
      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 eg: 
     session.FirstName = "some_firstname_from_db"; 
     //... 

     session.CreatedAt = DateTime.Now; 
     session.DisplayName = "Mauricio Leyzaola"; 
     session.Email = "[email protected]"; 
     session.FirstName = "Mauricio"; 
     session.IsAuthenticated = true; 
     session.LastName = "Leyzaola"; 
     session.UserName = "mauricio.leyzaola"; 
     session.UserAuthName = session.UserName; 
     var roles = new List<string>(); 
     roles.AddRange(new[] { "admin", "reader" }); 
     session.Roles = roles; 

     session.UserAuthId = "uniqueid-from-database"; 

     //base.OnAuthenticated(authService, session, tokens, authInfo); 

     authService.SaveSession(session, SessionExpiry); 
    } 
} 

này Trên chức năng Configure của AppHost Tôi đang thiết lớp xác thực tùy chỉnh của tôi để sử dụng nó như là mặc định. Tôi đoán tôi nên tạo một lớp khác và thêm nó ở đây là tốt, để xử lý các kịch bản token.

  Plugins.Add(new AuthFeature(() => new CustomUserSession(), 
      new IAuthProvider[] { 
       new MyCredentialsAuthProvider(appSettings) 
      }, htmlRedirect: "~/Account/Logon")); 

Cho đến nay, ServiceStack đang hoạt động như mong đợi. Tôi có thể gửi một bài đăng đến/auth/thông tin đăng nhập thông qua tên người dùng và mật khẩu và nó lưu trữ thông tin này, vì vậy cuộc gọi tiếp theo đến một dịch vụ yêu cầu đã được ủy quyền, tuyệt vời cho đến nay!

Câu hỏi tôi cần biết là cách gọi (và có thể đặt ở đâu đó trong SS) người dùng đang đăng nhập từ Bộ điều khiển tài khoản của tôi. Nếu bạn thấy khối mã đầu tiên tôi đang cố gắng gọi dịch vụ web (có vẻ như tôi đang làm sai) và nó hoạt động, nhưng cuộc gọi tiếp theo tới bất kỳ dịch vụ web nào sẽ không được xác thực.

Vui lòng không chỉ cho tôi hướng dẫn về ServiceStack, tôi đã ở đó trong hai ngày qua và vẫn không thể hiểu được.

Cảm ơn rất nhiều trước.

Trả lời

3

Dưới đây là những gì tôi thường sử dụng:

Bạn có thể thay thế "Logon" phương pháp hành động với mã dưới đây:

public ActionResult Login(LogOnModel model, string returnUrl) 
    { 
     if (ModelState.IsValid) 
     { 
      try 
      { 
       var authService = AppHostBase.Resolve<AuthService>(); 
       authService.RequestContext = System.Web.HttpContext.Current.ToRequestContext(); 
       var response = authService.Authenticate(new Auth 
       { 
        UserName = model.UserName, 
        Password = model.Password, 
        RememberMe = model.RememberMe 
       }); 

       // add ASP.NET auth cookie 
       FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe); 

       return RedirectToLocal(returnUrl); 
      } 
      catch (HttpError) 
      { 
      } 
     } 

     // If we got this far, something failed, redisplay form 
     ModelState.AddModelError("", "The user name or password provided is incorrect."); 
     return View(model); 
    } 

...và các plugin:

  //Default route: /auth/{provider} 
      Plugins.Add(new AuthFeature(() => new CustomUserSession(), 
      new IAuthProvider[] { 
       new CustomCredentialsAuthProvider(), 
       new CustomBasicAuthProvider() 
      })); 

.... nhà cung cấp Auth lớp:

public class CustomCredentialsAuthProvider : CredentialsAuthProvider 
{ 
    public override bool TryAuthenticate(IServiceBase authService, string userName, string password) 
    { 
     return UserLogUtil.LogUser(authService, userName, password); 
    } 
} 

public class CustomBasicAuthProvider : BasicAuthProvider 
{ 
    public override bool TryAuthenticate(IServiceBase authService, string userName, string password) 
    { 
     return UserLogUtil.LogUser(authService, userName, password); 
    } 
} 

... cuối cùng, tiện ích logging lớp

internal static class UserLogUtil 
{ 
    public static bool LogUser(IServiceBase authService, string userName, string password) 
    { 
     var userService = new UserService(); //This can be a webservice; or, you can just call your repository from here 
     var loggingResponse = (UserLogResponse)userService.Post(new LoggingUser { UserName = userName, Password = password }); 

     if (loggingResponse.User != null && loggingResponse.ResponseStatus == null) 
     { 
      var session = (CustomUserSession)authService.GetSession(false); 
      session.DisplayName = loggingResponse.User.FName.ValOrEmpty() + " " + loggingResponse.User.LName.ValOrEmpty(); 
      session.UserAuthId = userName; 
      session.IsAuthenticated = true; 
      session.Id = loggingResponse.User.UserID.ToString(); 

      // add roles and permissions 
      //session.Roles = new List<string>(); 
      //session.Permissions = new List<string>(); 
      //session.Roles.Add("Admin); 
      //session.Permissions.Add("Admin"); 

      return true; 
     } 
     else 
      return false; 
    } 
} 
+0

Tôi không có một máy tính với VS để kiểm tra câu trả lời của bạn, mặc dù nó có vẻ tốt. Sẽ cố gắng tối nay. Cảm ơn! – coffekid

+0

Nó đã làm việc thực sự. Cảm ơn rất nhiều! – coffekid

Các vấn đề liên quan