FormsAuthentication.SignOut()がユーザーをログアウトしない


143

これに対して私の頭は少し長すぎました。ユーザーがFormsAuthentication.SignOutを使用してログアウトした後、サイトのページを閲覧できないようにするにはどうすればよいですか?私はこれがそれをすることを期待します:

FormsAuthentication.SignOut();
Session.Abandon();
FormsAuthentication.RedirectToLoginPage();

しかし、そうではありません。URLを直接入力しても、ページを閲覧できます。私はしばらくの間、自分でロールするセキュリティを使用していなかったので、これが機能しない理由を忘れています。


そのコードはそのままで問題ありません...ブラウザでクリックしてもサーバー上のページに再度アクセスすることはなく、ローカルにキャッシュされたバージョンのページを再ロードするだけです。以下のすべてのソリューションはその事実を無視しているようであり、実際にここで行っている以上のことは何もしていません。簡単に言うと...これまでのところ、キャッシュを確認しているユーザーを解決するこの質問に対する答えはありません。たとえば、jsまたはサーバー側の命令でキャッシュをクリアする方法があるとは思いません。
戦争

この回答あなたがしているサイトは、PENテストを失敗している場合は特に申し出をチェックするいくつかの方法を、:stackoverflow.com/questions/31565632/...
タイラーS. Loeper

回答:


211

呼び出し時にCookieはクリアされずFormsAuthentication.SignOut()、新しいリクエストごとに認証されるため、ユーザーは引き続きWebサイトを閲覧できます。MSのドキュメントでは、Cookieはクリアされると言われていますが、クリアされません、バグ?とまったく同じですがSession.Abandon()、cookieはまだ残っています。

コードを次のように変更する必要があります。

FormsAuthentication.SignOut();
Session.Abandon();

// clear authentication cookie
HttpCookie cookie1 = new HttpCookie(FormsAuthentication.FormsCookieName, "");
cookie1.Expires = DateTime.Now.AddYears(-1);
Response.Cookies.Add(cookie1);

// clear session cookie (not necessary for your current problem but i would recommend you do it anyway)
SessionStateSection sessionStateSection = (SessionStateSection)WebConfigurationManager.GetSection("system.web/sessionState");
HttpCookie cookie2 = new HttpCookie(sessionStateSection.CookieName, "");
cookie2.Expires = DateTime.Now.AddYears(-1);
Response.Cookies.Add(cookie2);

FormsAuthentication.RedirectToLoginPage();

HttpCookieSystem.Web名前空間にあります。MSDNリファレンス


18
これは私にとってはうまくいきます。ただし、ログイン時にFormsAuthentication CookieでDomainプロパティが設定されている場合、ログアウト時にCookieを期限切れにするときにも設定する必要があることに注意してください
Phil Hale

8
また、cookie1.HttpOnly = trueを
Dmitry Zaets

6
これは私にとってより良い解決策のようです:Response.Cookies [FormsAuthentication.FormsCookieName] .Expires = DateTime.Now.AddDays(-1);
ランディH.

7
@RandyH。既存のFormsAuthentication Cookieを新しい空のCookieでオーバーライドすると、クライアントがシステムクロックを戻しても、Cookieからユーザーデータを取得できなくなります。
Tri Q Tran

9
誰かがこれらすべてのコメントを組み合わせて回答にできますか?
David

22

x64igorとPhil Haseldenによる上記の投稿の2つを使用してこれを解決しました。

1. x64igorはログアウトを実行する例を示しました:

  • まず、ログアウトへの応答で空のCookieを返すことにより、認証CookieとセッションCookieクリアする必要があります。

    public ActionResult LogOff()
    {
        FormsAuthentication.SignOut();
        Session.Clear();  // This may not be needed -- but can't hurt
        Session.Abandon();
    
        // Clear authentication cookie
        HttpCookie rFormsCookie = new HttpCookie( FormsAuthentication.FormsCookieName, "" );
        rFormsCookie.Expires = DateTime.Now.AddYears( -1 );
        Response.Cookies.Add( rFormsCookie );
    
        // Clear session cookie 
        HttpCookie rSessionCookie = new HttpCookie( "ASP.NET_SessionId", "" );
        rSessionCookie.Expires = DateTime.Now.AddYears( -1 );
        Response.Cookies.Add( rSessionCookie );

2. Phil Haseldenが、ログアウト後のキャッシュを防ぐ方法の上記の例を示しました。

  • レスポンスを介してクライアント側のキャッシュ無効にする必要があります。

        // Invalidate the Cache on the Client Side
        Response.Cache.SetCacheability( HttpCacheability.NoCache );
        Response.Cache.SetNoStore();
    
        // Redirect to the Home Page (that should be intercepted and redirected to the Login Page first)
        return RedirectToAction( "Index", "Home" ); 
    }

1
この問題を解決するために仕事で丸一日無駄になりました。ログインすると、ログアウトボタンがコントローラーで誤ったアクションを呼び出し始めました(ログアウトではなくログイン)。ありがとう、これで問題は解決しました。開発環境:ASP.NET 4.51 MVC 5.1
Ako

1
いい答えだ!控えめな提案:使用されたセッションCookie x64igorをクリアするための形式を使用しますSessionStateSection sessionStateSection = (SessionStateSection)WebConfigurationManager.GetSection("system.web/sessionState"); HttpCookie sessionCookie = new HttpCookie(sessionStateSection.CookieName, "");。一般に、セッションCookie名はではありません"ASP.NET_SessionId"
ビスケット、16

20

内でweb.config承認セクションが適切に設定されていないように思えます。例については、以下を参照してください。

<authentication mode="Forms">
  <forms name="MyCookie" loginUrl="Login.aspx" protection="All" timeout="90" slidingExpiration="true"></forms>
</authentication>
<authorization>
  <deny users="?" />
</authorization>

これははるかに簡単な解決策です。私はこれを答えとしてマークします。1つのバージョンのコードが1つの異なるサーバーで動作するようになったので、ここで追加した他のプロパティを設定する必要はありませんでした。したがって、コードを変更することは正しい解決策ではなく、構成を変更する方が優れています。
Vladimir Bozic 2016

デフォルトでは、slidingExpirationはtrueに設定されています(msdn.microsoft.com/library/1d3t3c61(v=vs.100).aspx)。そして、これにより、タイムアウトで設定されたx分後に、Cookieが無効になります-SignOut()を介してユーザーがログオフされたときではありません。したがって、これはFormsAuthenticationを使用してユーザーをログオフするという望ましい動作にはなりません。私が間違っていたら訂正してください。
OlafW 2017

12

ここで重要なのは、「URLを直接入力した場合...」と言うことです。

デフォルトでは、フォーム認証では、ブラウザはユーザーのページをキャッシュします。したがって、ブラウザのアドレスボックスのドロップダウンから直接URLを選択するか、それを入力すると、ブラウザのキャッシュからページを取得し、サーバーに戻って認証/承認を確認することはできません。これに対する解決策は、各ページのPage_Loadイベント、またはベースページのOnLoad()でクライアント側のキャッシュを防ぐことです。

Response.Cache.SetCacheability(HttpCacheability.NoCache);

また、次のように呼び出すこともできます。

Response.Cache.SetNoStore();

11

私もこれに苦労したことがあります。

これは何が起こっているかの類似点です...新しいビジターであるJoeがサイトにアクセスし、FormsAuthenticationを使用してログインページからログインします。ASP.NETはJoeの新しいIDを生成し、Cookieを提供します。そのクッキーは家の鍵のようなもので、ジョーがその鍵を持って戻ってくる限り、彼は錠を開けることができます。各訪問者には、使用する新しいキーと新しいロックが与えられます。

ときFormsAuthentication.SignOut()に呼び出され、システムがキーを紛失するジョーに指示します。ジョーはもはや鍵を持っていないので、通常はこれでうまくいき、彼は入りません。

ただし、ジョーが戻っきて、キーを紛失した場合、彼は戻ってきます!

私が言えることから、ドアのロックを変更するようにASP.NETに指示する方法はありません!

私がこれに耐えられる方法は、セッション変数でジョーの名前を覚えることです。彼がログアウトすると、セッションを放棄するので、彼の名前はもうわかりません。後で、彼が許可されているかどうかを確認するために、私は彼のIdentity.Nameを現在のセッションの内容と単に比較します。それらが一致しない場合、彼は有効な訪問者ではありません。

つまり、Webサイトの場合はUser.Identity.IsAuthenticated、セッション変数もチェックせずに依存しないでください。


8
+ 1、これは「Cookieリプレイ攻撃」と呼ばれていると思います。FormsAuthentication.SignOutの制限に関する記事があります:support.microsoft.com/kb/900111
Dmitry

3
上記のリンクをたどろうとしている人にとって、それは死んでいる。WaybackMachineを使用してこのページのコピーをここで取得することができますが、すぐにユーザーをリダイレクトしようとします。web.archive.org/web/20171128133421/https://...
KILLAバイトの

7

多くの検索の後、これは最終的に私のために働いた。お役に立てば幸いです。

public ActionResult LogOff()
{
    AuthenticationManager.SignOut();
    HttpContext.User = new GenericPrincipal(new GenericIdentity(string.Empty), null);
    return RedirectToAction("Index", "Home");
}

<li class="page-scroll">@Html.ActionLink("Log off", "LogOff", "Account")</li>

私は何年もPHPでWebアプリケーションを開発してきました。だから私はMVCを初めて使用するのですが、私はそれが好きだと認めますが、誰かをログオフするほど簡単なことはとても難しいと思った人はいますか?このページの他のすべてのスクリプトを試してみましたが、これが機能した唯一のスクリプトです。投稿ありがとうございます!
アンソニーグリッグス2017

6

これは私のために働く

public virtual ActionResult LogOff()
    {
        FormsAuthentication.SignOut();
        foreach (var cookie in Request.Cookies.AllKeys)
        {
            Request.Cookies.Remove(cookie);
        }
        foreach (var cookie in Response.Cookies.AllKeys)
        {
            Response.Cookies.Remove(cookie);
        }
        return RedirectToAction(MVC.Home.Index());
    }

3

あなたが投稿したコードはフォーム認証トークンを正しく削除するはずなので、問題のフォルダー/ページは実際には保護されていない可能性があります。

ログインする前にページにアクセスできないことを確認しましたか?

使用しているweb.config設定とログインコードを投稿できますか?


3

私はすべてのページの基本クラスを作成していて、同じ問題が発生しました。次のようなコードがあり、動作しませんでした。トレースすることにより、リダイレクトされずに、RedirectToLoginPage()ステートメントから次の行に制御が渡されます。

if (_requiresAuthentication)
{
    if (!User.Identity.IsAuthenticated)
        FormsAuthentication.RedirectToLoginPage();

    // check authorization for restricted pages only
    if (_isRestrictedPage) AuthorizePageAndButtons();
}

2つの解決策があることがわかりました。FormsAuthentication.RedirectToLoginPage();を変更するか、することが

if (!User.Identity.IsAuthenticated)
    Response.Redirect(FormsAuthentication.LoginUrl);

または、以下を追加してweb.configを変更します

<authorization>
  <deny users="?" />
</authorization>

2番目のケースでは、トレース中に、コントロールが要求されたページに到達しませんでした。ブレークポイントに到達する前に、ログインURLにすぐにリダイレクトされます。したがって、SignOut()メソッドは問題ではなく、リダイレクトメソッドが問題です。

私はそれが誰かを助けることを願っています

よろしく


2
また、FormsAuthentication.RedirectToLoginPage()を呼び出した直後にResponse.End()を呼び出すこともできます
murki

MS側には少し誤解があると思います。ログインページに戻るには、ユーザーをロックアウトする必要があります。それ以外の場合、フレームワークは喜んでアクセスを許可します。したがって、この投稿でソリューション#2を言う必要があります。
Josh Robinson、

3

ここでいくつかの提案を試しましたが、ブラウザの戻るボタンを使用できたときに、メニュー選択をクリックすると、その[ActionResult]の[Authorize]トークンがログイン画面に戻りました。

これが私のログアウトコードです:

        FormsAuthentication.SignOut();
        Response.Cookies.Remove(FormsAuthentication.FormsCookieName);
        Response.Cache.SetExpires(DateTime.Now.AddSeconds(-1));
        HttpCookie cookie = HttpContext.Request.Cookies[FormsAuthentication.FormsCookieName];
        if (cookie != null)
        {
            cookie.Expires = DateTime.Now.AddDays(-1);
            Response.Cookies.Add(cookie);
        }

ブラウザーの戻る機能を使用すると、セキュリティで保護されたメニューが表示され、表示されます(まだ作業中です)、アプリでセキュリティで保護された操作を行うことができませんでした。

お役に立てれば


ありがとう。これは私のために働いた解決策です(<deny users="?" />web.configでは必要ありません)
Alexei

3

私はこのスレッドでほとんどの答えを試しましたが、運はありません。これで終わりました:

protected void btnLogout_Click(object sender, EventArgs e)
{
    FormsAuthentication.Initialize();
    var fat = new FormsAuthenticationTicket(1, "", DateTime.Now, DateTime.Now.AddMinutes(-30), false, string.Empty, FormsAuthentication.FormsCookiePath);
    Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(fat)));
    FormsAuthentication.RedirectToLoginPage();
}

ここで見つかりました:http : //forums.asp.net/t/1306526.aspx/1


3

この回答は、技術的にはKhosro.Pakmaneshと同じです。私はそれを投稿して、彼の回答がこのスレッドの他の回答とどのように異なるか、およびどのユースケースで使用できるかを明確にします。

一般に、ユーザーセッションをクリアするには、

HttpContext.Session.Abandon();
FormsAuthentication.SignOut();

ユーザーを効果的にログアウトします。ただし、同じリクエスト内で確認する必要がある場合Request.isAuthenticated(たとえば、承認フィルターで頻繁に発生する可能性があります)、次のことがわかります

Request.isAuthenticated == true

あなたがやった後でHttpContext.Session.Abandon()FormsAuthentication.SignOut()

効果があったのは

AuthenticationManager.SignOut();
HttpContext.User = new GenericPrincipal(new GenericIdentity(string.Empty), null);

効果的に設定しますRequest.isAuthenticated = false


2

これは、でauthentication> forms> Pathプロパティを設定したときに起こりましたWeb.config。これを削除すると問題が修正FormsAuthentication.SignOut();され、単純なものでもCookieが削除されました。


1

あるサブドメイン(sub1.domain.com)からログインして、別のサブドメイン(www.domain.com)からログアウトしようとしている可能性があります。


1

SignOut()がチケットを適切に削除できなかったように見える、同じ問題が発生しました。しかし、他のロジックがリダイレクトを引き起こした特定の場合のみ。この2番目のリダイレクトを削除した後(エラーメッセージに置き換えました)、問題は解消しました。

問題は、ページが間違ったタイミングでリダイレクトされ、認証がトリガーされなかったことにあります。


1

私は現在同様の問題を抱えており、私の場合と元のポスターの問題はリダイレクトが原因であると考えています。デフォルトでは、Response.Redirectは例外を引き起こし、キャッチされるまで即座にバブルし、リダイレクトがすぐに実行されます。これが、変更されたCookieコレクションがクライアントに渡されないようにしていると思います。コードを変更して使用する場合:

Response.Redirect("url", false);

これにより例外が防止され、Cookieがクライアントに正しく送信されるようになります。


1

ログインを押したときにセッション変数を送信してみてください。そして、ウェルカムページで、最初に、ページのロードまたはInitイベントでそのセッションが次のように空であるかどうかを確認します。

if(Session["UserID"] == null || Session["UserID"] == "")
{
    Response.Redirect("Login.aspx");
}

1

私にとっては、次のアプローチが機能します。「FormsAuthentication.SignOut()」ステートメントの後にエラーがあると、SingOutが機能しないと思います。

public ActionResult SignOut()
    {
        if (Request.IsAuthenticated)
        {
            FormsAuthentication.SignOut();

            return Redirect("~/");
        }
        return View();
     }

0

IEを使用してこの動作をテストまたは確認していますか?IEがこれらのページをキャッシュから提供している可能性があります。IEにキャッシュをフラッシュさせることは悪名高いことです。そのため、多くの場合、ログアウトした後でも、「保護された」ページのいずれかのURLを入力すると、以前にキャッシュされたコンテンツが表示されます。

(別のユーザーとしてログインした場合でもこの動作が見られ、IEのページ上部に「ようこそ」バーが表示され、古いユーザーのユーザー名が表示されます。現在では、通常、再読み込みによって更新されますが、永続的な場合、それはまだキャッシュの問題である可能性があります。)


0

Session.abandon()を実行してCookieを破棄すると、かなりうまくいきます。私はmvc3を使用していますが、保護されたページに移動してログアウトし、ブラウザの履歴からアクセスすると問題が発生するようです。大したことではありませんが、それでもやや迷惑です。

私のWebアプリのリンクをたどるのは正しい方法ですが。

ブラウザのキャッシュを行わないように設定するのがよいでしょう。


0

MVCの場合、これは私にとってはうまくいきます:

        public ActionResult LogOff()
        {
            FormsAuthentication.SignOut();
            return Redirect(FormsAuthentication.GetRedirectUrl(User.Identity.Name, true));
        }

0

問題を理解するのに役立つ情報を追加したかったのです。フォーム認証では、ユーザーデータをCookieまたはURLのクエリ文字列に格納できます。サイトがサポートする方法は、web.configファイルで構成できます。

マイクロソフトによると

SignOutメソッドは、CookiesSupportedがfalseの場合、フォーム認証チケット情報をCookieまたはURLから削除します

同時に、彼らは言う

アプリケーションがcookielessフォーム認証用に構成されているかどうかを示すHttpCookieMode値の1つ。デフォルトはUseDeviceProfileです

最後に、UseDeviceProfileに関して、彼らは言う

CookieModeプロパティがUseDeviceProfileに設定されている 場合、 現在のリクエストのブラウザがCookieとCookieによるリダイレクトの両方をサポートしていれば、CookiesSupportedプロパティはtrueを返します。それ以外の場合、CookiesSupportedプロパティはfalseを返します。

ユーザーのブラウザーによっては、これをすべてつなぎ合わせると、デフォルトの構成でCookiesSupportedがtrueになる場合があります。になるがあり。これは、SignOutメソッドがCookieからチケットをクリアしないことを意味します。これは直観に反するようで、なぜこのように機能するのかわかりません。どのような状況でも、SignOutが実際にユーザーをサインアウトすることを期待します。

サインアウト自体を機能させる1つの方法は、web.configファイルでCookieモードを「UseCookies」に変更することです(つまり、Cookieが必要です)。

<authentication mode="Forms">
  <forms loginUrl="~/Account/SignIn" cookieless="UseCookies"/>
</authentication>

私のテストによると、これを行うと、サイトを犠牲にしてSignOut自体が機能するようになり、Cookieが正しく機能するようになります。


あなたはそれを間違って読んでいると思います。SignOut()については、CookiesSupportedがfalseの場合はURLからクリアされ、それ以外の場合はCookieからクリアされることを意味します。つまり、「SignOutメソッドはフォーム認証チケット情報をCookieから、またはCookiesSupportedがfalseの場合はURLから削除します。」
Oskar Berggren

-1

STSからのwsignoutcleanupメッセージがIISからのアプリケーションの名前とURLが一致しない場合、WIF はブラウザにCookieのクリーンアップを拒否することに注意してください。つまり、CASE SENSITIVEです。WIFは緑のOKチェックで応答しますが、Cookieを削除するコマンドをブラウザーに送信しません

したがって、URLの大文字と小文字の区別に注意を払う必要があります。

たとえば、ThinkTecture Identity Serverは、アクセスしているRPのURLを1つのCookieに保存しますが、すべて小文字にします。WIFは小文字でwsignoutcleanupメッセージを受け取り、IISのアプリケーション名と比較します。一致しない場合、Cookieは削除されませんが、ブラウザーにOKが報告されます。したがって、このIdentity Serverでは、このような問題を回避するために、すべてのURLをweb.configに、すべてのアプリケーション名をIISに小文字で書き込む必要がありました。

また、STSのサブドメイン外にアプリケーションがある場合は、ブラウザーでサードパーティのCookieを許可することを忘れないでください。許可しないと、WIFが指示した場合でもブラウザーはCookieを削除しません。


1
WIF?STS?ThinkTecture Identity Server?これらのすべては何ですか、そしてそれらがこの質問にどのように関係していますか?
Oskar Berggren
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.