ServiceStack を介して HTML ページと Web サービスを提供する ASP MVC アプリケーションのアーキテクチャを解決するのに問題があります。
アプリケーションは " http://myapplication.com " などのベース URL に存在し、SS は " http://myapplication.com/api " に存在します。両方を構成する最も簡単な方法だからです。
一般的にはすべて正常に動作しますが、承認と認証の部分に到達すると、行き詰まります。
1 つには、ASP が通常 FormsAuthentication を介して Cookie を処理する必要があり、ユーザーはログイン画面を通過し、属性「Authorize」が使用されているときにアクションとコントローラーを使用できます。これは典型的なASPなので、「 http://myapplication.com/PurchaseOrders 」などで問題ありません。
一方、アプリケーションのクライアントは、javascript から Web サービス API を使用します。これらの Web サービスは、ServiceStack の属性「Authenticate」でタグ付けされる場合もあります。たとえば、「http://myapplication.com/api/purchaseorders/25」は、ユーザーがその特定の注文書を表示できるかどうかを検証する必要があります。それ以外の場合は、401 Unauthorized を送信して、JavaScript がそれらのケースを処理し、エラー メッセージを表示できるようにします。
最後になりましたが、別のユーザー グループが、任意の外部アプリケーション (おそらく Java または .NET) を使用して、トークンによって私の API を利用します。そのため、2 種類の認証を解決する必要があります。1 つはユーザー名とパスワードを使用し、もう 1 つはトークンを使用して永続化します。これにより、最初に認証されると、次の呼び出しは 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 に投稿を送信すると、この情報が保存されるため、サービスへの次の呼び出しでは、リクエストは既に承認されています。
私が知る必要がある質問は、Account コントローラーからログインしているユーザーを呼び出す (そしておそらく SS のどこかに設定する) 方法です。コードの最初のブロックが表示された場合、Web サービスを呼び出そうとしていますが (間違っているように見えます)、動作しますが、Web サービスへの次の呼び出しは認証されていないように見えます。
私に ServiceStack のチュートリアルを教えないでください。私は過去 2 日間そこにいましたが、まだ理解できません。
よろしくお願いします。