1

このアプリケーションでは、役割ベースのフォーム認証を実装しました。これはRoleModuleを使用して処理されており、RoleデータをCookieに保存し、Cookieからデータを読み取ってオブジェクトをインスタンス化するたびに行われIPrincipalます。このコードは次のApplication_OnPostAcquireRequestStateメソッドで実行されます。

 HttpApplication application = source as HttpApplication;
 HttpContext context = application.Context;

if (context.User.Identity.IsAuthenticated &&
      (!Roles.CookieRequireSSL || context.Request.IsSecureConnection))
{
//Read the roles data from the Roles cookie..

context.User = new CustomPrincipal(context.User.Identity, cookieValue);
Thread.CurrentPrincipal = context.User;
}

これにより、context.Userオブジェクトが初期化されます。サーバーにリクエストが送信されるたびに、ユーザーは上記のフローを使用して認証されます。では、Application_EndRequestRolesCookieを現在のプリンシパルオブジェクトデータで更新します。

このページには、Cookieを読み取り、Cookieを更新し、有効期限が切れた場合にチケットを更新するFormsAuthentication_OnAuthenticate方法があります。Global.asaxまた、このメソッドでは、チケットの有効期限が切れた場合に、セッションオブジェクトにユーザー名の値を設定しようとします。

FormsAuthentication oldTicket = FormsAuthentication.Decrypt(context.Request.Cookies[FormsAuthentication.FormsCookieName].Value);
if(oldTicket != null)
{
    if(oldTicket.Expired)
    {
        try
        {
            HttpContext.Current.Session["UserName"] = userName;
        }
        catch
        {
            //Log error.
        }

    FormsAuthentication newTicket =  new FormsAuthenticationTicket(oldTicket.Version, oldTicket.Name, DateTime.Now,
            DateTime.Now.AddMinutes(30), oldTicket.IsPersistent, oldTicket.UserData);

    string encryptedTicket = FormsAuthentication.Encrypt(newTicket);
    HttpCookie httpCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
    if (isPersistent)
    {
        httpCookie.Expires = DateTime.Now.AddMinutes(300);
    }
}

web.configのフォーム設定は次のとおりです。

   <forms defaultUrl="Default.aspx" domain="" loginUrl="Login.aspx" name=".ASPXFORMSAUTH" timeout="20" slidingExpiration="true" />

セッションタイムアウトは20分です。

問題:ユーザーが30分(FormsAuthチケットの更新期間)を超えてアイドル状態になっているcontext.User.Identity.IsAuthenticated場合、ロールモジュールの値はfalseであり、context.Userとして設定されNULLます。これで、ユーザーがページを要求すると、ログインページにリダイレクトされます。ただし、Cookieはまだ存在します。この場合も、ユーザーがページをリクエストしようとすると、context.User.IsAuthenticatedプロパティがに設定されtrue、ユーザーはそれぞれのページに移動します。また、FormsAuthentication_OnAuthenticateメソッドでは、セッション値を設定しようとすると、セッションオブジェクトがであるためエラーがスローされますNULL

ここで達成したいのは、永続的なCookieの場合、認証チケットがタイムアウトした後、ユーザーはログアウトしない、つまりユーザーを再認証する必要があるということです。

どうすればこれを達成できますか?私が間違っていなければ、設定context.Userは目的を解決するはずですが、どうすればそれを実行できますか?

追加情報:

チケットの有効期限が切れてページをリクエストしようとすると、イベントビューアに次のエラーメッセージが表示されます。

Event code: 4005 
Event message: Forms authentication failed for the request. Reason: The ticket supplied has expired. 
Event time: 08-02-2012 20:02:05 
Event time (UTC): 08-02-2012 14:32:05 
Event ID: 048e3238ade94fd6a7289bac36d130ef 
Event sequence: 76 
Event occurrence: 2 
Event detail code: 50202 

Process information: 
Process ID: 21692 
Process name: w3wp.exe 
Account name: IIS APPPOOL\ASP.NET v4.0 Classic 

自動生成されたものではなく、web.configに保存されている標準のマシンキー設定を使用しています。また、すべてのエラーについてプロセスIDと同じものを確認しました。

4

1 に答える 1

1

私はついに問題を解決しました。何が起こっていたのかというと、FormsAuthenticationチケットがタイムアウトしたときに、AuthenticateイベントのMSDNドキュメントFormsAuthentication_OnAuthenticateで指定されているように、context.Userオブジェクトを設定できませんでした。

FormsAuthentication_OnAuthenticateイベント中にUserプロパティの値を指定しない場合、CookieまたはURLでフォーム認証チケットによって提供されるIDが使用されます。

その理由はticket.Name、ユーザーのユーザー名で設定していないためです。空の文字列です。FormsIdentityしたがって、AuthenticateイベントがユーザーのIDを取得して、インスタンスを作成できなかった場合があります。解決策として、期限切れのチケットを更新するときに、GenericIdentityオブジェクトを作成し、それを使用してを設定しcontext.Userます。

IIdentity identity = new GenericIdentity(username, "Forms");
context.User = new CustomPrincipal(identity);
于 2012-02-11T16:54:55.203 に答える