【发布时间】:2013-08-21 15:04:58
【问题描述】:
我在解决通过 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 教程,我过去两天一直在那里,仍然无法弄清楚。
非常感谢。
【问题讨论】:
标签: c# .net authentication forms-authentication servicestack