我在解决通过 ServiceStack 为 html 页面和 Web 服务提供服务器的 ASP MVC 应用程序的体系结构时遇到问题。
应用程序位于基本 URL 中,例如“ http://myapplication.com ”,SS 位于“ http://myapplication.com/api ”中,因为这是配置两者的最简单方法。
一般来说,一切正常,但是当我到达授权和身份验证的部分时,我就陷入了困境。
一方面,我需要应用程序处理 cookie,因为 ASP 通常通过 FormsAuthentication 进行操作,并且用户将通过登录屏幕并在使用“授权”属性时可以使用操作和控制器。这是典型的 ASP,所以我对它没有任何问题,例如“ http://myapplication.com/PurchaseOrders ”。
另一方面,我的应用程序的客户端将从 javascript 使用我的 Web 服务 api。在某些情况下,这些 Web 服务也将使用 ServiceStack 的“Authenticate”属性进行标记。例如,“ http://myapplication.com/api/purchaseorders/25 ”必须验证用户是否可以查看该特定采购订单,否则发送 401 Unauthorized 以便 javascript 可以处理这些情况并显示错误消息。
最后但同样重要的是,另一组用户将通过令牌使用我的 API,使用任何外部应用程序(可能是 Java 或 .NET)。所以我需要解决两种类型的身份验证,一种使用用户名和密码,另一种使用令牌并使其持久化,这样一旦它们第一次通过身份验证,接下来的调用就可以更快地从 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();
}
至于身份验证提供程序,我正在使用此类
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 = "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<string>();
roles.AddRange(new[] { "admin", "reader" });
session.Roles = roles;
session.UserAuthId = "uniqueid-from-database";
//base.OnAuthenticated(authService, session, tokens, authInfo);
authService.SaveSession(session, SessionExpiry);
}
}
在 AppHost 的配置功能上,我将自定义身份验证类设置为默认使用。我想我应该创建另一个类并将其也添加到此处,以处理令牌场景。
Plugins.Add(new AuthFeature(() => new CustomUserSession(),
new IAuthProvider[] {
new MyCredentialsAuthProvider(appSettings)
}, htmlRedirect: "~/Account/Logon"));
到目前为止,ServiceStack 正在按预期工作。我可以向 /auth/credentials 提交一个帖子,传递用户名和密码,它会存储这些信息,所以下次调用服务请求已经被授权,到目前为止很棒!
我需要知道的问题是如何调用(并且可能在 SS 中的某处设置)从我的帐户控制器登录的用户。如果您看到我正在尝试调用 Web 服务的第一个代码块(看起来我做错了)并且它可以工作,但是对任何 Web 服务的下一次调用看起来未经身份验证。
请不要将我指向 ServiceStack 教程,我过去两天一直在那里,但仍然无法弄清楚。
提前非常感谢。