by WebSurfer
2011年2月5日 16:48
ASP.NET の承認は、"ユーザー" に加えて "ロール" というレベルでの管理をサポートしています。ロール管理では、ユーザーをロールに割り当てることにより、ユーザーのグループを単位として扱うことができます。 詳しくは MSDN ライブラリの ASP.NET のロールによる承認の管理 が参考になると思います。
Forms 認証の場合は、サイト管理者がロールを定義し、ロール情報は SQL Server などのデータベースに格納します。
一方、Windows 認証の場合は Windows アカウントを利用しますので、ロールはそのユーザーが属するグループになります。従って、ロールを定義するのはサーバーの管理者で、ロール情報は Active Directory ドメインコントローラーに格納されるということになります。
当然、Windows 認証の場合もロールによるアクセス制限は可能です。例えば、あるフォルダにロールによるアクセス制限をしておくと、そのロールに属さないユーザーがフォルダ内のページを要求すると下の画像のようなダイアログが出てきます。
ロールによるアクセス制限は、Forms 認証と同様に web.config で定義します。フォルダ直下の web.config に以下のような定義をしておくと、Domain Users グループに属するユーザー以外のアクセスは拒否されます。
<configuration>
<system.web>
<authorization>
<allow roles="<ドメイン名>\Domain Users" />
<deny users="*" />
</authorization>
</system.web>
</configuration>
なお、Windows 認証の場合、web.config でロールを有効にする(web.config で <roleManager enabled="true" /> とする)のは意味がなさそうです。というより、そういう設定はしてはいけないようです。
web.config でロールを有効にすると、Page.User は System.Security.Principal.IPrincipal ではなく、それから派生した System.Web.Security.RolePrincipal になります。そこで WindowsPrincipal オブジェクトを取得するため (WindowsPrincipal)User とすると、"型 'System.Web.Security.RolePrincipal' のオブジェクトを型 'System.Security.Principal.WindowsPrincipal' にキャストできません。" というエラーになりますので。
ここからは先は余談です。
Windows アカウントでは、ユーザーもグループもセキュリティ識別子 (SID) を認識に用いています。よく知られた SID は MSDN ライブラリの Windows サーバー オペレーティング システムの既知のセキュリティ識別子 に一覧がありますので見てください。
SID は S-1-1-0 のように人間にとっては意味不明の文字列ですが、これを Everyone のように ACL エディタで使われている名前に変換する方法を忘れないように書いておきます。
Everyone のような名前は NTAccount オブジェクトから取得できます。NTAccount オブジェクトは IdentityReference.Translate メソッドで取得できます。その例を以下のコードに示します。これを実行すると、上の画像のように表示されます。
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Security.Principal" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
WindowsPrincipal principal = (WindowsPrincipal)User;
// IsInRole("S-1-2-35-545") ではダメ。
if (principal.IsInRole("BUILTIN\\Users"))
{
Label1.Text = "BUILTIN\\Users";
}
WindowsIdentity identity =
(WindowsIdentity)principal.Identity;
SecurityIdentifier sid = identity.Owner;
StringBuilder sb = new StringBuilder();
NTAccount nt = (NTAccount)sid.Translate(typeof(NTAccount));
sb.Append("ユーザーの SID: " + nt.Value +
" (" + sid.ToString() + ")<br /><br />");
sb.Append("ユーザーが属するグループ<br />");
IdentityReferenceCollection irc = identity.Groups;
foreach (IdentityReference ir in irc)
{
NTAccount ntAccount =
(NTAccount)ir.Translate(typeof(NTAccount));
sb.Append(" " + ntAccount.Value +
" (" + ir.Value + ")<br />");
}
Label2.Text = sb.ToString();
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
ユーザ: <asp:LoginName ID="LoginName1" runat="server" />
<br />
ロール: <asp:Label ID="Label1" runat="server" />
<hr />
<h1>Windows Users のページ</h1>
<asp:Label ID="Label2" runat="server" />
<hr />
<asp:HyperLink ID="HyperLink1"
runat="server"
NavigateUrl="~/Default.aspx">
入り口に戻る
</asp:HyperLink>
</div>
</form>
</body>
</html>
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 イベント以前のタイミングになります。