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.
nie mam komputer z VS, aby przetestować twoją odpowiedź, mimo że wygląda dobrze. Spróbuję dziś wieczorem. Dzięki! – coffekid
Rzeczywiście zadziałało. Wielkie dzięki! – coffekid