2013-08-21 11 views
5

Mam problemy rozwiązywania architekturę aplikacji ASP MVC że serwery stron HTML i usług internetowych poprzez ServiceStack.ServiceStack API i ASP MVC uwierzytelniania dwojako

Aplikacja znajduje się w bazowym adresie URL, np. "http://myapplication.com", a SS w "http://myapplication.com/api", ponieważ jest to najprostszy sposób konfiguracji obu.

W ogóle wszystko działa poprawnie, ale kiedy dotarłem część autoryzacji i uwierzytelniania, gdzie utknąłem.

Po pierwsze, potrzebuję plików cookie obsługi aplikacji, ponieważ ASP zwykle wykonuje uwierzytelnianie za pomocą formularzy, a użytkownicy przechodzą przez ekran logowania i mogą korzystać z akcji i kontrolerów, gdy używany jest atrybut "Autoryzuj". Jest to typowe dla ASP, więc nie mam z tym problemu, na przykład "http://myapplication.com/PurchaseOrders".

Z drugiej strony, klienci mojego wniosku pochłonie moje API usługi sieci Web z javascript. Te serwisy internetowe będą również w niektórych przypadkach otagowane atrybutem "Uwierzytelnij" usługi ServiceStack. Na przykład "http://myapplication.com/api/purchaseorders/25" musiałby sprawdzić, czy użytkownik może wyświetlić to zamówienie, w przeciwnym razie wyśle ​​401 Nieautoryzowane, aby javascript mógł obsłużyć te przypadki i wyświetlić komunikat o błędzie.

Last but not least, inna grupa użytkowników będzie korzystać z mojego API za pomocą tokena, za pomocą dowolnej aplikacji zewnętrznej (prawdopodobnie Java lub .NET). Dlatego muszę rozwiązać dwa rodzaje uwierzytelniania, jeden przy użyciu nazwy użytkownika i hasła, drugi za pomocą tokena i sprawić, by były trwałe, więc gdy zostaną uwierzytelnione za pierwszym razem, następne połączenia są szybsze do rozwiązania z interfejsu API.

Jest to kod, który do tej pory, mam umieścić go w bardzo prosty sposób, aby wyraźny przykład.

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

Jak dla dostawcy uwierzytelniania Używam tej klasy

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

Z funkcji Konfiguruj AppHost ja ustawienie mojego niestandardową klasę uwierzytelniania używać go jako domyślny. Sądzę, że powinienem stworzyć kolejną klasę i dodać ją również tutaj, aby obsłużyć scenariusz tokena.

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

Do tej pory ServiceStack działa zgodnie z oczekiwaniami. Mogę przesłać post do/auth/poświadczeń przekazujących nazwę użytkownika i hasło i przechowuje tę informację, więc następnym razem zadzwoń do serwisu, którego wniosek jest już autoryzowany, świetny do tej pory!

Pytanie, które muszę wiedzieć, to w jaki sposób zadzwonić (i prawdopodobnie ustawić gdzieś w SS) użytkownika, który loguje się z mojego kontrolera konta. Jeśli widzisz pierwszy blok kodu, próbuję wywołać usługę sieciową (wygląda na to, że robię to źle) i działa, ale następne wywołanie dowolnej usługi sieciowej wygląda na nieuwierzytelnione.

Proszę nie wskaż mnie ServiceStack tutoriale, byłem tam przez ostatnie dwa dni i wciąż nie mogę zrozumieć.

Dziękuję bardzo z góry.

Odpowiedz

3

Oto co zwykle używać:

można zastąpić "Logon" metody działania z poniższym kodzie:

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

...oraz wtyczki:

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

.... dostawcę logowania:

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

... wreszcie, narzędzie rejestrowania klasa

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

nie mam komputer z VS, aby przetestować twoją odpowiedź, mimo że wygląda dobrze. Spróbuję dziś wieczorem. Dzięki! – coffekid

+0

Rzeczywiście zadziałało. Wielkie dzięki! – coffekid

Powiązane problemy