2011年4月7日木曜日

ブチザッキさんへ

お元気ですか。ボクは元気です。

OData and Authentication – Part 7 – Forms Authentication - WCF Data Services Team Blog - Site Home - MSDN Blogs

WCF Data Servicesをプロキシクラス経由で呼び出すときにForm認証してやんよ、の件についてなんですけども。

WCF Data Services で フォーム認証を利用する « ブチザッキ

ナニをナニする系で、ナニしてみたのでご覧いただけたら幸いです。

Custom Membership Providers - Task Manager - CodeProject

プロキシからの呼び出しに介入し、別リクエストでAuthentication_JSON_AppService.axdを呼び出すことでForm認証し、レスポンスからCookieを横取りすることで、認証チケット再利用する部分を、FormsAuthenticationクラスを使って認証チケットを発行してそちらを使うことで実現してみました。

とはいえ、まったく楽チン度と便利さが上がらなかったので、ボツにしようかと思ったのですが、それはそれで少し寂しくなっちゃったので、公開レターの形式にしてみました。

WCF DataServicesをホストするサーバーサイドプロジェクトをASP.NET MVCにして、HomeControllerに以下のアクションメソッドを追加します。

[HttpPost]
public ContentResult FormAuth(string userName, string password)
{
  if (Membership.ValidateUser(userName, password))
  {
    var authTicket = new FormsAuthenticationTicket(
       1,
       userName,
       DateTime.Now,
       DateTime.Now.AddMinutes(30),
       false,
       userName);
    var cookie = 
       FormsAuthentication.FormsCookieName + "=" +
       FormsAuthentication.Encrypt(authTicket) + "; path=" +
       FormsAuthentication.FormsCookiePath + "; " +
       (!FormsAuthentication.RequireSSL
         ? "HttpOnly" : "");
    return Content(cookie);
  }

  return null;
}

続いて、クライアントサイドのプロキシクラス用に実装しているGetCookieの代わりとなる部分を以下のように。

string GetTicket(string userName, string password)
{
  string loginUri = string.Format("{0}/{1}/{2}",
      ServiceUri,
      "Home",
      "FormAuth");
  WebRequest request = HttpWebRequest.Create(loginUri);
  request.ContentType = "application/x-www-form-urlencoded";
  request.Method = "POST";

  string authBody = String.Format(
      "userName={0}&password={1}",
      userName,
      password);
  request.ContentLength = authBody.Length;

  using (StreamWriter w = new StreamWriter(request.GetRequestStream()))
  {
      w.Write(authBody);
      w.Close();

      WebResponse res = request.GetResponse();
      var body = new StreamReader(res.GetResponseStream()).ReadToEnd();
      if (!string.IsNullOrEmpty(body))
      {
          Cookie = body;
      }
      else
      {
          throw new Exception("Invalid username and password");
      }
  }

  return Cookie;
}

GetCookie(userName,password)の部分を上記のGetTicket(userName,password)にすることで、Cookie横取りではなくなりますね。

formauth

だから言ったじゃないですか!ボツにしたかったって...。

dotnetConf2015 Japan

https://github.com/takepara/MvcVpl ↑こちらにいろいろ置いときました。 参加してくださった方々の温かい対応に感謝感謝です。