Je rencontre des difficultés pour résoudre l'architecture d'une application ASP MVC qui gère les pages html et les services Web via ServiceStack. L'application vit dans l'URL de base, par exemple "http://myapplication.com" et SS dans "http://myapplication.com/api" parce que c'est la manière la plus simple de configurer les deux.API ServiceStack et authentification ASP MVC de deux manières
En général tout fonctionne bien, mais quand j'ai atteint la partie de l'autorisation et l'authentification, est où je suis coincé. Pour un, j'ai besoin de l'application gérer les cookies comme ASP normalement fait par FormsAuthentication, et les utilisateurs passeraient par un écran de connexion et pourraient consommer des actions et des contrôleurs lorsque l'attribut "Autoriser" est utilisé. Ceci est typique d'ASP, donc je n'ai aucun problème avec celui-ci, comme "http://myapplication.com/PurchaseOrders". En revanche, les clients de mon application vont consommer mon API de service Web à partir de javascript. Ces services Web seront également étiquetés dans certains cas avec l'attribut "Authenticate" de ServiceStack. Par exemple "http://myapplication.com/api/purchaseorders/25" devra valider si l'utilisateur peut voir cette commande particulière, sinon envoyer un 401 non autorisé afin que javascript puisse gérer ces cas et afficher le message d'erreur.
Enfin et surtout, un autre groupe d'utilisateurs utilisera mon API par un token, en utilisant n'importe quelle application externe (probablement Java ou .NET). J'ai donc besoin de résoudre deux types d'authentification, l'un en utilisant le nom d'utilisateur et le mot de passe, l'autre par le jeton et de les rendre persistants. Une fois authentifiés la première fois, les prochains appels sont plus rapides à résoudre depuis l'API.
C'est le code que j'ai jusqu'à présent, je l'ai mis très simplement pour clarifier l'exemple.
[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();
}
En ce qui concerne le fournisseur d'authentification J'utilise cette classe
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);
}
}
Sur la fonction Configurer des apphost Je suis en train de ma classe d'authentification personnalisé pour l'utiliser comme la valeur par défaut. Je suppose que je devrais créer une autre classe et l'ajouter ici, pour gérer le scénario du jeton.
Plugins.Add(new AuthFeature(() => new CustomUserSession(),
new IAuthProvider[] {
new MyCredentialsAuthProvider(appSettings)
}, htmlRedirect: "~/Account/Logon"));
Jusqu'à présent, ServiceStack fonctionne comme prévu. Je peux envoyer un message à/auth/credentials en passant le nom d'utilisateur et le mot de passe et il stocke cette information, donc, lors d'un prochain appel à un service, la requête est déjà autorisée, super jusqu'à présent!
La question que je dois savoir est comment appeler (et probablement placer quelque part dans SS) l'utilisateur qui se connecte à partir de mon contrôleur de compte. Si vous voyez le premier bloc de code que j'essaie d'appeler le service Web (semble que je le fais mal) et cela fonctionne, mais le prochain appel à n'importe quel service Web semble non authentifié. S'il vous plaît ne me pointez pas vers les tutoriels ServiceStack, je suis là depuis deux jours et je n'arrive toujours pas à le comprendre.
Merci beaucoup d'avance.
Je ne dispose pas d'un ordinateur VS pour tester votre réponse, même si ça a l'air bien. Je vais essayer ce soir. Merci! – coffekid
Cela a fonctionné réellement. Merci beaucoup! – coffekid