ServiceStack API和ASP MVC身份validation有两种方式

我在解决通过ServiceStack服务html页面和Web服务的ASP MVC应用程序的体系结构时遇到了麻烦。

该应用程序存在于基本URL中,例如“ http://myapplication.com ”,SS存在于“ http://myapplication.com/api ”中,因为它是配置两者的最简单方法。

一般来说一切正常,但是当我到达授权和身份validation的一部分时,我就被困住了。

首先,我需要应用程序处理cookie,因为ASP通常会执行FormsAuthentication,并且当使用属性“Authorize”时,用户将通过登录屏幕并使用操作和控制器。 这是典型的ASP,所以我没有问题,例如“ http://myapplication.com/PurchaseOrders ”。

另一方面,我的应用程序的客户端将从javascript使用我的Web服务API。 在某些情况下,还会使用ServiceStack的“Authenticate”属性标记这些Web服务。 例如,“ http://myapplication.com/api/purchaseorders/25 ”必须validation用户是否可以查看该特定采购订单,否则发送401 Unauthorized,以便javascript可以处理这些情况并显示错误消息。

最后但并非最不重要的是,另一组用户将使用任何外部应用程序(可能是Java或.NET)通过令牌使用我的API。 因此,我需要解决两种类型的身份validation,一种使用用户名和密码,另一种使用令牌并使其持久化,因此一旦第一次进行身份validation,下一次调用就可以更快地从API中解决。

这是我到目前为止的代码,我已经非常简单地说明了这个例子。

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

至于身份validation提供程序,我正在使用此类

  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 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 = "mauricio.leyzaola@gmail.com"; session.FirstName = "Mauricio"; session.IsAuthenticated = true; session.LastName = "Leyzaola"; session.UserName = "mauricio.leyzaola"; session.UserAuthName = session.UserName; var roles = new List(); roles.AddRange(new[] { "admin", "reader" }); session.Roles = roles; session.UserAuthId = "uniqueid-from-database"; //base.OnAuthenticated(authService, session, tokens, authInfo); authService.SaveSession(session, SessionExpiry); } } 

在AppHost的配置function我设置自定义身份validation类以将其用作默认值。 我想我应该创建另一个类并在此处添加它来处理令牌场景。

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

到目前为止,ServiceStack正在按预期工作。 我可以通过用户名和密码向/ auth /凭证提交一个post并存储这些信息,所以下次调用服务请求已经被授权,到目前为止很棒!

我需要知道的问题是如何调用(并且可能在SS中的某个位置)从我的帐户控制器登录的用户。 如果您看到我尝试调用Web服务的第一个代码块(看起来我做错了)并且它可以工作,但是对任何Web服务的下一次调用看起来都是未经身份validation的。

请不要指向ServiceStack教程,过去两天我一直在那里,但仍然无法弄明白。

非常感谢提前。

这是我通常使用的:

您可以使用以下代码替换“登录”操作方法:

  public ActionResult Login(LogOnModel model, string returnUrl) { if (ModelState.IsValid) { try { var authService = AppHostBase.Resolve(); 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); } 

……和插件:

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

…. Auth提供者类:

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

…最后,日志实用程序类

 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(); //session.Permissions = new List(); //session.Roles.Add("Admin); //session.Permissions.Add("Admin"); return true; } else return false; } }