by WebSurfer
2010年7月30日 08:37
あまり役に立たないかもしれませんが、ASP.NET 標準の Forms 認証システムで、認証チケットが期限切れになっているかどうかを判定するという話です。なお、前提条件としてクッキーが有効になっていることを想定しています。
例えば、一旦認証を受けたユーザーが、ログオフせず、ブラウザを立ち上げたまま、長時間席を外すなどして、タイムアウトに設定した時間を超えてアクセスしなかった場合を考えてください。
ユーザーが席に戻ってきて再度アクセスした場合、アクセスしたページに匿名アクセスを許可してなければ、ログインページにリダイレクトされるというのが Forms 認証の通常の設定です。
そこで、ユーザーに認証チケットが期限切れとなっていることを知らせるにはどうしたらいいでしょうか?
User.Identity.IsAuthenticated ではダメです。認証されているか否かは判定できますが、認証チケットが期限切れかどうかはわかりませんから。
一旦認証を受けたが、認証チケットが期限切れになっているというのは、サーバー側では以下の条件で判定できるはずです。
-
要求 HTTP ヘッダーに認証クッキーが含まれる。
-
認証クッキーの中の認証チケットが期限切れ。
認証クッキーと認証チケットは違うことに注意してください。クッキーはチケットの入れ物に過ぎません。認証チケットの有効期限は、認証クッキーの Value の中に入っている情報の一つです。HttpCookie.Expires ではありません。
一般的に、一旦認証クッキーの発行を受ければ、セッションが切れない限り(注)、次の要求の時にブラウザはサーバーにクッキーを送ります。(注:認証クッキーを「永続化」している場合は話が違ってきます。詳しくは別の記事「Froms 認証クッキーの永続化」を見てください)
認証クッキーを取得し、その Value を復号して認証チケットを取得し、ユーザー名、期限切れか否かなどの情報を取得できます。それで上記の 2 つの条件を確認できます。例えば、ログインページにリダイレクトされたときに期限切れを知らせる場合は、Global.asax で以下のようにします(もしくは HTTP Module を作る)。
void FormsAuthentication_Authenticate(object sender,
FormsAuthenticationEventArgs args)
{
// "/login.aspx" は実際に合わせて適宜変更してください。
if (Request.CurrentExecutionFilePath != "/login.aspx")
{
return;
}
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
if (null == authCookie)
{
return;
}
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch (Exception ex)
{
return;
}
if (null == authTicket)
{
return;
}
if (authTicket.Expired)
{
// 知らせるための処置を書く。例えば下記:
Context.Response.Write("<h1><font color=red>" +
"Forms Authentication Ticket Expired" +
"</font></h1><hr>");
}
}
認証チケットが期限切れの場合、FormsAuthenticationModule が認証クッキーを削除しているようで、タイミングによっては認証クッキーは取得できないので注意してください。
従って、認証クッキーを取得できるのは、FormsAuthenticationModule.Authenticate イベント以前のタイミングになります。
by WebSurfer
2010年7月29日 12:26
SqlParameter を SqlParameterCollection に追加する際、SqlParameterCollection.Add メソッドを使って以下のように設定することがよくあると思います。
command.Parameters.Add("@CustomerID", SqlDbType.NChar, 5, "CustomerID");
command.Parameters.Add("@CompanyName", SqlDbType.NVarChar, 40, "CompanyName");
この時、3 つめの引数の SqlParameter.Size プロパティの値はどのようにすべきでしょうか? 例えば、フィールドの定義が nchar(5) だったら、上記のように 5 にすべきでしょうか? SqlDbType.Int だったら 4 にすべきでしょうか?
個人的には、特に必要がない限り 0 に統一しておくのがよいと思います。理由は以下のとおりです。
-
固定長データ型では、Size の値は無視される。
-
可変長データ型では、Size はサーバーに送信するデータの最大量を示す。ただし、0 の場合は制限しない。
「0 の場合は制限しない」というところが要注意です。MSDN ライブラリにはそのことは書いてありませんが、検証して確認しました。また、自動生成される TableAdapter のコードの中では、可変長データ型のデータも含めてすべて 0 が使われていますので、間違いないと思います。
わざわざ調べて意味のない(どのみち無視される)情報を書いたり、場合によっては不適切な値を書いたり、必要がある場合と見分けがつかなくなったり・・・というのは、どう考えても面白くないですよね?
通常 0 を使うと決めておけば、0 以外の数字が入っている時はそれなりの意味がある(設定する必要があるので数字が入っている)ということがすぐ分かります。
ただし、固定長データ型で情報として利用するとか、可変長データ型でサーバーに送信する文字数を切り詰めるなど、値を指定することに意味があるケースもあるようです。
詳しくは、MSDN ライブラリの SqlParameter.Size プロパティ を参照してください。(リンク先は .NET 3.0 のものです。.NET 4.0 は若干書いてあることが違います。仕様が変わったのかどうかは不明(未調査)です。)
by WebSurfer
2010年7月28日 14:43
ASP.NET の ImageButton コントロールを配置したページを W3C Markup Validation Service で検証すると、「あなたが使用しているドキュメントタイプではサポートされていない属性(border="0")が使われている」というエラーが出ます。
ドキュメントタイプは ASP.NET のデフォルトで、XHTML 1.0 Transitional と宣言しています。border 属性の使用は、Strict ではダメですが、Transitional では許されているはずなんですが・・・
それはともかく、オリジナルの *.aspx コードにはそのような属性を指定していないにも関わらず、何故 ASP.NET が border="0" という古い属性のコードを書き出すのでしょう?
それは、W3C Markup Validation Service から ASP.NET が要求を受けた際、要求元を古いブラウザと解釈するからだそうです。
ちなみに、IE8 や Firefox 3.6.7 などの新しいブラウザから同じページを要求すると、style="border-width:0px;" となって、XHTML1.0 Strict でも有効な HTML/CSS のコードになります。
この件は ASP.NET Forum にもレポートされていて、回避策も書かれています。リンク切れになると困るのでここにもその回避策を書いておきます。(2011/8/20追記: MSDN ライブラリ にも対応方法が書いてありました。下の追記参照)
アプリケーション・ルート直下に App_Browsers フォルダを設け、その中に以下の内容の .browser ファイルを配置します。これによって ASP.NET は W3C Markup Validation Service に対して IE8 や Firefox 3.6.7 と同じコードを送信するようになるはずです。
<browsers>
<browser id="w3cValidator" parentID="default">
<identification>
<userAgent match="^W3C_Validator" />
</identification>
<capture>
<userAgent match="^W3C_Validator/(?'version'(?'major'\d+)(?'minor'\.\d+)\w*).*" />
</capture>
<capabilities>
<capability name="browser" value="w3cValidator" />
<capability name="majorversion" value="${major}" />
<capability name="minorversion" value="${minor}" />
<capability name="version" value="${version}" />
<capability name="w3cdomversion" value="1.0" />
<capability name="xml" value="true" />
<capability name="tagWriter" value="System.Web.UI.HtmlTextWriter" />
</capabilities>
</browser>
</browsers>
なお、上記は ASP.NET 3.5 の話で、ASP.NET 4.0 でどうなっているかは未確認です。
------ 2011/8/20 追記 ------
MSDN ライブラリの Visual Studio と ASP.NET の XHTML 標準 の「マークアップ検証に対するブラウザー機能の構成」というセクションに、本件に関する記述がありました。
.NET Framework 4 の記事なので、サーバを ASP.NET 4 にアップグレードしても、ブラウザー定義を追加しての対応は必要なようです。
なお、そこで紹介されている W3C 検証用のブラウザ定義は以下の通りです。
<browsers>
<browser id="W3C_Validator" parentID="default">
<identification>
<userAgent match="^W3C_Validator" />
</identification>
<capabilities>
<capability name="browser" value="W3C Validator" />
<capability name="ecmaScriptVersion" value="1.2" />
<capability name="javascript" value="true" />
<capability name="supportsCss" value="true" />
<capability name="tables" value="true" />
<capability name="tagWriter"
value="System.Web.UI.HtmlTextWriter" />
<capability name="w3cdomversion" value="1.0" />
</capabilities>
</browser>
</browsers>
W3C のホームページの User's guide for the W3C Markup Validator によると、通常の User-Agent は W3C_Validator/xx.xxxx とのことなので、MSDN ライブラリのブラウザ定義の方が適切だと思います。