Hatena::ブログ(Diary)

三日坊主と呼ばせない!日記 このページをアンテナに追加 RSSフィード

2012-01-31

[]WebSecurityクラスを理解する:(3)サンプル実装を追ってみる-その2

今回はいよいよサンプルのコードを追ってみます。

ただし、単にソースを追いかけても面白く無いと思います。...ので、この「スターターサイト」テンプレートに対して、ちょっとだけ仕様を追加・変更する事を例に挙げながら、やってみようと思います。



「スターターサイト」に対して追加・変更する仕様

  • ログイン時に利用するIDを、メールアドレス無く英数字からなる一意の「ログインID」とする
    • メールアドレスも保持する
  • ユーザ情報として、氏名と年齢の入力を受け付ける
  • ログインIDは変更させないが、その他の氏名、年齢、メールアドレスは変更可能にする
  • 情報を格納するファイル名を「StarterSite.sdf」ではなく「MySite.sdf」とする
  • ユーザ情報を格納するテーブル名は「UserInfo」とする

情報の粒度が若干アレですが、とりあえずは上記を実装することを目標にしたいと思います。




1:第一歩、WebSecurityの初期化コード

WebSecurityクラスに関わるまず最初の一歩は、「_AppStart.cshtml」から始まります。

ASP.NET Web Pagesにおいて先頭が「_(アンダースコア)」から始まるファイルはちょっと特殊なファイルという扱いになっています。例えばブラウザから直接アクセスしても、表示することができません。

それらのうち、「_AppStart.cshtml」という名前のファイルはさらに特別扱いされていて、『ブラウザからいかなるファイルにアクセスがあった際にも必ず最初に実行される』という性質があります。

例えば「~/Default.cshtml」というファイルがあって、ブラウザから「http://localhost/Default.cshtml」とアクセスしたときにでも、まず先に暗黙で_AppStart.cshtmlが先に呼び出されてからDefault.cshtmlが呼び出される、という動きになります。

すなわち、この_AppStart.cshtmlに書かれているコードは必ず最初に実行される、という事になります。



ではこのファイルを開いて中を見てみましょう。左のファイル一覧から_AppStart.cshtmlをダブルクリックすると、開くことができます。

すると、

  • @{}で囲まれたコードブロックが一つある
  • コードブロックの一行目に「WebSecurity.InitializeDatabaseConnection」の記述がある
  • 2行目から、WebMailクラスを使った記述が書かれ、コメントアウトされている

事が見て取れると思います。

もちろん、注目するのはWebSecurity.InitializeDatabaseConnectionの行です。

WebSecurity.InitializeDatabaseConnection("StarterSite", "UserProfile", "UserId", "Email", true);

こんな風に書いてあると思います。


ここで、WebSecurity.InitializeDatabaseConnectionのリファレンスを見てみましょう。

WebSecurity.InitializeDatabaseConnection Method (WebMatrix.WebData)


引数の個数が違うオーバーロードがありますが、とりあえず一つ目(引数の数が少ない方)を見てみてください。

せっかくですので引数の意味を一つ一つ見ていきましょう。こっちです。

WebSecurity.InitializeDatabaseConnection Method (String, String, String, String, Boolean) (WebMatrix.WebData)


  • 第1引数:connectionStringName(接続文字列

文字通り、データベースの接続文字列を指定します。

SQL Server CEの場合は、拡張子抜きのファイル名で指定します。
SQL Server等のデータベースを使う場合は、Web.ConfigのconnectionStringsセクションに記述した接続情報を指定するNameを書きます。

今回のサンプルコードを見てみると、"StarterSite"と書いてあります。前回確認した通りこのサンプルが規定で持っているSQLCEのファイル名は"StarterSite.sdf"ですので、ここではこのSQLCEのファイルを指定していることがわかります。


  • 第2引数:userTableName(ユーザテーブル名)

これも文字通りユーザ情報を格納するテーブル名を指定します。

サンプルコードには"UserProfile"と書いてありますね。これも前回確認した、ユーザ情報が格納されていうテーブルと一致していると思います。ユーザ情報を格納するテーブル名を変更する(した)場合は、ここも変更する必要があります。


  • 第3引数:userIdColumn(ユーザID格納カラム名

第2引数で指定したテーブルにて、ユーザIDを格納するカラムの名前を指定します。ここで指定されたカラムに格納される値は、webpages_Membership等関連テーブルとのリレーションのキーになりますし、WebSecurityクラスの各種プロパティメソッドで「UserID」として利用されます。(たとえば、CurrentUserIdプロパティ等)。変更することでユーザIDとして使用するカラムの名前を変更することができますが、型はintである必要があります。


  • 第4引数:userNameColumn(ユーザ名称格納カラム名)

第3引数と同様、ユーザ名として利用されるカラムの名称を指定します。ここで指定されたカラムに格納される値はWebSecurityクラスの各種メンバで、UserNameとして利用されます。通常、ログインIDとして利用されたりします。


  • 第5引数:autoCreateTables(ユーザテーブル名)

最後の引数は、自動的にユーザテーブルを作成するかどうかです。trueを指定すると、同名のテーブルがデータベースに存在していない場合に自動作成されます。なお作成されるのは第2引数で指定された名称のユーザーテーブルだけではなく、webpages_Membership等のwebpages_*のテーブルについても同様です。ただし、trueを指定した場合でも「データベース自身」は自動作成されません。データべース自体はいかなる場合でもあらかじめ作成しておく必要があります。




以上で、引数の役割が理解できたと思います。割と単純だったのではないでしょうか?これが理解できると、先に挙げた今回試みる予定の仕様変更についても、いくつかここでやっておく必要があることに気が付くかもしれません。


…が、今はとりあえずここまでにして、もうちょっとだけ先に進みます。


ちなみに、今回触れなかった、引数が一つ多いオーバーロードについては、以前に日記で触れていますのでそちらも参照してください。

2012-01-28

[][]Script#のLTしてきました

1/28に行われた「Okayama-js第二回」に参加して、LTで登壇させていただきました。内容はScript#についての軽い紹介です。


資料はこちらからどうぞ。


なお、あとで見てみたらコードが一切なくてこれだけ見ても全然雰囲気がわからない事に気が付来ました(^^;当日お見せしたコードは基本的に以下のページの「sample code」からダウンロードできるものと同じですので、そちらを参照してみてください。

Getting Started with Script#


見ていただくとお分かりの通り、サンプルソースの解説も行われていますので、上記ページ自体もとても参考になると思います。




LTではネタ気味に紹介しましたが、これ自体は使いどころを押さえればとても有効に使えるものではないかと思います。

資料の方にも書きましたが、2011年のMIX11でのNikhilk氏が登壇したセッションビデオもあります(英語ですが)。

Script#: Compiling C# to JavaScript using Visual Studio

2012-01-23

[]WebMatrix.Data.StronglyTypedとな!?

※シリーズ(?)の途中というかまだ始まってもない感じですが、ちょっと別の話題です。忘れないうちのメモです。

@ishisaka さんのtweetで知ったのですが、上記のとおり、WebMatrix.Data.StronglyTyped なるものがあるとか。

https://github.com/JeremySkinner/WebMatrix.Data.StronglyTyped/tree/master/src/WebMatrix.Data.StronglyTyped

名前からもご想像に難くないとも追いますが、以下の通り、WebMatrix.Data.Databaseでクエリを投げたときに、型付けされたオブジェクトに反してくれるとう素敵ライブラリのようです。

http://www.jeremyskinner.co.uk/2011/01/24/strongly-typed-data-access-with-webmatrix-data/ から抜粋すると、

public class User {
  public int Id { get; set; }
  public string Surname { get; set; }
  public string Forename { get; set; }
  public string FullName {
    get { return Surname + ", " + Forename; }
  }
}

こんな風にエンティティクラスを作っておいて、

using(var db = Database.Open("MyDatabase")) {
   var users = db.Query<User>("select Id, Surname, Forename from Users");
   foreach(var user in users) {
     Console.WriteLine(user.FullName);
   }
}

という感じで使えるみたい。


で、Nugetのパッケージも公開されてるようですので、さっそく使ってみました

http://nuget.org/packages/WebMatrix.Data.StronglyTyped




これはなかなか素敵!!

2012-01-19

[]WebSecurityクラスを理解する:(2)サンプル実装を追ってみる-その1

とりあえず、どんな機能があって、どういう風に実装していくのか、サンプルコードをベースに見ていきましょう。

今回は、実際に細かくソースを見ていく前の下準備をしたいと思います。

具体的には、

  • Web Matrixのインストール
  • 「スターターサイト」テンプレートの展開
  • 「スターターサイト」テンプレートの構成の確認
  • ちょっとした動作確認

という具合に、順をおってやっていきたいと思います。



1:WebMatrixのインストール

今回は、せっかくなので(?)Web Matrixでやってみたいと思います。Web Matrixとは、Microsoftがリリースしている無償のWebアプリケーション開発環境です。

http://www.microsoft.com/web/webmatrix/

上記サイトにアクセスして、「今すぐダウンロード」をクリックして下さい。

f:id:kiyokura:20120119230935p:image

※サイトデザインが変わったりして、変更されている場合もあるかと思いますが、そんな感じのボタンかリンクを探してみてください。



そうすると今度は「Web Platform Installer」(移行、WebPIと省略)というツールがダウンロード・実行されます。

f:id:kiyokura:20120119230938p:image

このWebPIから、WebMatrixをインストールすることになります。

f:id:kiyokura:20120119231315p:image

ボタンを数回クリックするだけでインストールされますので、そのまま進めて行けばインストールが完了します。


WebMatrixのセットアップについては、以下などが参考になると思います。

http://www.forest.impress.co.jp/docs/special/20110901_473168.html

WebMatrixそのものの解説や、WebPIについての簡単な解説もありますので、ぜひ、ご覧になることをお奨めします。


またVisual Studioや無償版のVisual Web Developerでやりたい方も、以降についてははっきり言ってほとんど同じです。コードなどについてもほぼそのまま読んでいただけると思います*1。が、もしまだ使ったことがなえれば、ぜひWeb Matrixも試してみてください。


2:サンプルコードの準備

では、WebMatrixでサンプルコードを展開してみましょう。

WebMatrixを起動してクイックスタート画面が表示されたら、その中にある「テンプレートからサイトを作成する」をクリックしてください。

f:id:kiyokura:20120119231316p:image

テンプレートがいくつか並んだ画面が表示されますので、そのなかから「スターターサイト」を選んでください。ちなみに下記画面のように[スターターサ...]と表示される場合は、一方が日本語版でもう一方が英語版です。

f:id:kiyokura:20120119231317p:image

今回のは正直どちらでも変わらないのですが、右側が日本語なので、日本語が良い場合はそちらを選んでください。サイト名を変更したい場合は入力し、OKボタンを押してください。




テンプレートの展開が終わったら、こんな感じで画面が表示されると思います。

f:id:kiyokura:20120119231318p:image


3:サンプルサイトの構造

実行する前に、サンプルサイトの構造をちょっと見てみましょう。

WebMatrixの左のメニューから、Fileをクリックしてください。

f:id:kiyokura:20120119232226p:image

これですね。

すると、左側にファイルビューが展開されます。フォルダをすべて展開すると、こんな感じです。

f:id:kiyokura:20120119232227p:image

これが、このスターターサイトに含まれている全てのファイルになります。

「Account」フォルダの下にそれっぽい名前のファイルが沢山ありますが、お察しの通りログインユーザ登録などの機能はここにサンプルとして実装されています。…というよりむしろ、ユーザ登録周りしか無いサンプルと言っても差し支えないでしょう*2


また、「App_Data」フォルダのはいかにも注目してください。StarterSite.sdfというのがあります。この拡張子sdfというファイルは、SQL Server Compact Edition(以下SQLCE)用のデータベースファイルです。SQLCEは軽量のSQLデータベースエンジンで、SQL ServerやMySQLなどのようにサーバサービス)を必要とせず、アプリケーションに組み込む形で利用できるものです。2012年1月現在の最新版であるVer4.0から、ASP.NETのアプリケーションでも利用できるようになりました。このASP.NET Web Pagesでも利用できます。


ついでに、このStarterSite.sdfに何が入っているかも見ておきましょう。WebMatrixには、SQLCEのファイルの中身のテーブルをGUI操作する機能があります。

左のメニューから、[データベース]を選択してください。

f:id:kiyokura:20120119232228p:image

ツリー形式でStarterSite.sdfが表示されるので、▲マークをどんどんクリックしてドリルダウンしてみてください。

f:id:kiyokura:20120119232229p:image

テーブルが4つあるのがわかると思います、このうち、上の二つ「UserProfile」と「webpages_Membership」が、今回の対象となるWebSecurityクラスが関係するものになります。

残り二つも全く無関係ではないのですが、名前のとおりRole(役割)に関するもので、直接WebSecurityクラスの持つ機能とは関係ありません。これらについてもいつか機会があれば取り上げたいと思いますが、気になる方はこちらのドキュメントなどを参照してください。


ちなみに、Wisual Studioでやった場合は、App_Code配下のDBファイルがSQL Server用のDBファイル「StarterSite.mdf」になっていますが、それ以外はたぶん同じと思います。


4:ちょっと触ってみよう

実際にコードを見ていく前に、少し動作を確認してみましょう。WebMatrixの上部のリボンにある、「実行」ボタンをクリックしてください。ブラウザーが起動し以下のような画面が表示されると思います。

f:id:kiyokura:20120119232230p:image


実行した画面の右上に注目すると、[登録]と[ログイン]というリンクがありますね。せっかくなので、ユーザを登録してログインしてみましょう。

右上のリンク[登録]をクリックしてください。

下記のような、ユーザ―登録画面が表示されました。

f:id:kiyokura:20120119232758p:image

ログインIDとしてのメールアドレスパスワードを入力して登録するだけのとても単純な登録画面です(下の方にCAPTCHAの記述とかありますが、とりあえず無視してください)。


では早速、登録してみましょう。適当に入力して、登録をクリックしてください。入力にエラーが無ければ登録完了し、ログインされた状態でトップページに戻ってきた状態になっていると思います。

f:id:kiyokura:20120119232759p:image

右上を見ると、さっきと様子が変わっていて[へようこそ <メールアドレス>][ログアウト]となっていて、ログイン状態にあることが解ります*3

この状態で[へようこそ <メールアドレス>]の部分をクリックするとパスワード変更機能が利用できますし、[ログアウト]をクリックするとログアウトします。もちろん、再度ログインすることも可能です。色々と操作してみてください。



サンプルで実装されている基本的なユーザ登録やログインの操作のうち、ごくごく基本の部分の動きや機能なこんな感じです。



まとめ

今回は

  • Web Matrixのインストール
  • 「スターターサイト」テンプレートの展開
  • 「スターターサイト」テンプレートの構成の確認
  • ちょっとした動作確認

をやってみました。

いよいよ次回から、この基本の動きをソースコードから追いつつ、さらに少しカスタマイズも行いながらWebSecurityクラスを理解していきたいと思います。

*1Visual Studio/Visual Web Developerの場合の導入方法などは、こちらを参照。http://msdn.microsoft.com/ja-jp/asp.net/hh180212

*2:まあサンプルというか、テンプレートですので。

*3:『へようこそ<メールアドレス>』となっているのはきっと、Welcome hogehogeという英語のを直訳して語順を直さなかったというおちゃめさんだと思います

2012-01-17

[] WebSecurityクラスを理解する:[1]WebSedurityクラスとは?

Blogにもぽつぽつと投稿していますが、ここ最近、ASP.NET Web Pagesをよく触っています。

このASP.NET Web Pages『カジュアルなWebアプリケーションフレームワークとしてはよくできているなー』というのが、ここ最近触ってみての改めての感想です。


その一端に、WebSecurityクラスによるユーザ認証機能があります。

とても簡単にログイン認証やユーザー登録などの機能を自分のアプリケーションに実装することが出来るような機能を提供するもので、WebMatrixの「スターターサイト」やVisual Studioの「ASP.NET Webページ(Razor)」テンプレートで展開されるサンプル実装でもこれが使われています。


このしばらく、このサンプルをいじりまわしながらカスタマイズしたり機能を調べたりしていましたので、せっかくなのでその調べた事をここでシェアしてみたいと思います。


WebSecurityクラスの概要

まずは、MSDNリファレンスを見てみましょう。

http://msdn.microsoft.com/en-us/library/webmatrix.webdata.websecurity%28v=vs.99%29.aspx


まず、メンバが列挙されています。

そんなに数が無く、比較的シンプルそうなのが解ります。そんなに数が無い…とはいえ、一つ一つメンバを列挙して解説するのも面白くないし面倒なので、これらは後々触れることにします。

とりあずぱっと見て目につくのは、WebSecurityクラスのメンバすべてstatic(VBでいえばShared)なメンバであることでしょうか。C#でいうと、WebSecurityクラス自体がstaticです。



次にRemarkを見ると…ASP.NET Web Pagesのリファレンスには珍しく、結構な文章量があります。

しばらくは邦訳されそうにない気がするので*1、ざっくり目を通してみると概ね以下のようなことが読み取れます。

  • 機能を絞って実装され非常にシンプルだけど最低限必要な機能が用意されているものであること
  • セキュリティも意識された実装になっていること
    • クリアテキストでパスワードを保持するオプションは無い
    • ログイン失敗が続くと自動的にアカウントを一定時間ロックする昨日があること…など。
  • ややこしい手順を踏まなくても、ちょっとした拡張が容易に出来る事、既存のユーザ情報テーブルなどとの親和性も高いこと
    • ユーザの一意IDやEmail、その他の任意のユーザの情報(氏名等の追加の属性)と、パスワードや管理のための情報を分割して管理する仕組みになっていること
    • IDをキーにして既存のユーザー情報テーブルと統合することも容易な構造であること
  • アカウントの登録やパスワードの変更、パスワード忘れに対する救済策などを実現する機能があること
  • 役割(Role)に関する機能もWebSecurityクラスは持っていないため、別のもの(SimpleRoleProvider等)を使って行ってほしいこと

要は『機能を絞ってシンプルにし、それでいてセキュリティに配慮しつつも、容易に拡張できるようなっているよ』という感じでしょうか。


また、ASP.NETに詳しい人向けの情報として『このクラスの機能を実現するために低レベルの部分ではASP.NET標準のMembershipProviderの実装を使っている』ことなども書かれており、深く理解するための情報として有用かもしれません(ただし、WebSecurityの基底クラスにMembershipProviderがあるわけではありません。WebSecurityクラスは、同じくWebMatrix.WebData名前空間にある、SimpleMembershipProviderを”利用”する実装が行われているクラスです。そしてSimpleMembershipProviderの基底クラスにMembershipProviderがある、という構図と思われます)。



Remakrsの下には、少しだけサンプルコードが提供されています。WebSecurityのLoginメソッドを使ってログインを行っているサンプルですが、さすがに…これだけだと、ちょっと雰囲気がつかみにくいかもしれませんね。お奨めは、先にも挙げたとおりWebMatrixやVisual Studioのテンプレートに含まれているサンプル実装です。

次回(?)からしばらく、このサンプルテンプレートを元に、WebSecurityクラスの全貌に迫っていこうかと思います。

*1:何となくですが、なんかそんな気がする…

2012-01-15

[][] .NET Frameworkでメールアドレスをチェックする正規表現

よくいろんなところにあるけど、MSDNライブラリにもあることを知った。

http://msdn.microsoft.com/ja-jp/library/01escwtf.aspx#Y200

C#版とVB.NET版がありました)

RFC2822完全準拠ではない気がしますが、「hoge+fuga/foo=bar@example.com」とかのRFC 5322でいうmailbox形式や「"hoge\ fuga"@example.com」みたいなquoted-stringにも対応してるようなので、大抵はこれで行けるような気がします。


ちなみに、当然ですが「au..docomo.@example.com」な感じの例の奴もきっちり弾けるのでご安心ください(?)


RCF2822にばっちり準拠した正規表現が欲しい方は、PerlとJavascript用になりますが小飼弾氏の 「PHP使いはもう正規表現をblogに書くな」と言わせないでくれ を参照ください。

[][]ASP.NET Web Pagesの入力フォームでタグ等の入力を受け入れる


ASP.NETの入力フォームに対する既定のバリデーション

ASP.NETでは以前から*1、既定の動作として入力フォームに対してフレームワーク側でバリデーションを行い、例えばタグとして解釈できるもの("<"と">"で囲まれた文字)等がある場合、HttpRequestValidationException 発生させるようになっています。

例えば、emailという名前のinput要素に『hoge <hoge@example.com>』と入力した場合、

危険な可能性のある Request.Form 値がクライアント (email="hoge <hoge@example.com>") から検出されました。

のように、HttpRequestValidationException が発生します。


『余計なお世話』と感じる方もいるかもしれませんが、『既定の動作をより安全な方に傾ける』という実装ですので、これはフレームワークの既定の動作としては正しい実装だと思います。



Web Pages(Razor)で検証させずに受け取る方法

ただしこのままだと、当然ですがタグ入力を受け入れたい場合等には仕様を満たせません。『フレームワーク側でバリデーションされないようしたい』という事は往々にして発生するでしょう。

例えば、上記のメールアドレスの入力*2を受け取ろうと思した場合、通常は以下のように受け取ると思いますが、このままですと上記の通りの例外が発生します

var email = Request.Form["email"];

では、Web Pages(Rasor)では、どうやって受け取れば良いか。

Web PagesではRequestオブジェクトにUnvalidatedという拡張メソッドがあり、これを使うことで、受け取る一つ一つのフォーム値に対して、『これは安全でなくても受け取る』という指定をしながら受け取ることができいます。

例えば以下のようなコードになります。

var email = Request.Unvalidated().Form["email"];

詳細については以下のMSDNドキュメントを参照ください:

http://msdn.microsoft.com/en-us/library/gg568738(v=vs.99).aspx

*1:多分、ASP.NET2.0から

*2:『hoge <hoge@example.com>』はRFC2822的にはValidなメールアドレス表現です。もちろん、これを受け入れるかどうかはアプリケーションの仕様次第ですが:p