FormsAuthentication.SignOut () tidak mengeluarkan pengguna

143

Memukul kepalaku terlalu lama. Bagaimana cara mencegah pengguna menelusuri halaman situs setelah mereka keluar menggunakan FormsAuthentication.SignOut? Saya berharap ini melakukannya:

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

Tapi ternyata tidak. Jika saya mengetikkan URL secara langsung, saya masih bisa menjelajah ke halaman. Saya belum pernah menggunakan keamanan roll Anda sendiri, jadi saya lupa mengapa ini tidak berhasil.

Jason
sumber
Kode itu baik-baik saja seperti ... mengklik kembali di browser tidak mengunjungi kembali halaman di server itu hanya memuat ulang versi halaman cache lokal. Semua solusi di bawah ini tampaknya mengabaikan fakta itu dan tidak benar-benar melakukan apa pun lebih dari yang Anda lakukan di sini. Singkatnya ... tidak ada jawaban untuk pertanyaan ini yang akan menyelesaikan pengguna melihat cache mereka sampai saat ini saya tidak percaya ada cara untuk menghapus cache di katakan ... js atau dengan instruksi sisi server.
Perang
Jawaban ini menawarkan beberapa cara untuk memeriksa, terutama jika situs Anda gagal dalam tes PEN: stackoverflow.com/questions/31565632/…
Tyler S. Loeper

Jawaban:

211

Pengguna masih dapat menjelajahi situs web Anda karena cookie tidak dihapus ketika Anda menelepon FormsAuthentication.SignOut()dan mereka diautentikasi pada setiap permintaan baru. Dalam dokumentasi MS disebutkan bahwa cookie akan dihapus tetapi tidak, bug? Persis sama dengan Session.Abandon(), cookie masih ada.

Anda harus mengubah kode Anda menjadi ini:

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();

HttpCookieada di System.Webnamespace. Referensi MSDN .

Igor Jerosimić
sumber
18
Ini bekerja untuk saya. Namun perlu dicatat bahwa jika properti Domain telah disetel pada cookie FormsAuthentication saat masuk, itu juga perlu ditetapkan saat kedaluwarsa cookie pada saat Anda logout
Phil Hale
8
Juga jangan lupa cookie1.HttpOnly = true;
Dmitry Zaets
6
Ini sepertinya solusi yang lebih baik bagi saya: Response.Cookies [FormsAuthentication.FormsCookieName] .Expires = DateTime.Now.AddDays (-1);
Randy H.
7
@RandyH. Mengganti cookie FormsAuthentication yang ada dengan cookie kosong baru memastikan bahwa meskipun klien memutar kembali jam sistem mereka, mereka masih tidak dapat mengambil data pengguna apa pun dari cookie.
Tri Q Tran
9
Bisakah seseorang menggabungkan semua komentar ini ke dalam jawabannya?
David
22

Menggunakan dua dari posting di atas oleh x64igor dan Phil Haselden memecahkan ini:

1. x64igor memberi contoh untuk melakukan Logout:

  • Pertama-tama Anda harus menghapus Cookie Otentikasi dan Cookie Sesi dengan mengirimkan kembali cookie kosong dalam Respons terhadap Logout.

    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 memberi contoh di atas tentang cara mencegah caching setelah logout:

  • Anda perlu memvalidasi Cache di Sisi Klien melalui Respons .

        // 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" ); 
    }
justdan23
sumber
1
Terbuang sepanjang hari di tempat kerja untuk menyelesaikan masalah ini. Setelah login, tombol logout mulai memanggil tindakan yang salah di controller (Login bukan Logout). Terima kasih, ini menyelesaikan masalah. Lingkungan pengembangan: ASP.NET 4.51 MVC 5.1
Ako
1
Jawaban yang bagus! Saran Humble: Gunakan forma untuk kliring cookie sesi x64igor digunakan: SessionStateSection sessionStateSection = (SessionStateSection)WebConfigurationManager.GetSection("system.web/sessionState"); HttpCookie sessionCookie = new HttpCookie(sessionStateSection.CookieName, "");. Secara umum, nama cookie sesi tidak "ASP.NET_SessionId".
seebiscuit
20

Bagi saya sepertinya Anda tidak memiliki bagian otorisasi web.config Anda diatur dengan benar di dalamnya. Lihat di bawah untuk contoh.

<authentication mode="Forms">
  <forms name="MyCookie" loginUrl="Login.aspx" protection="All" timeout="90" slidingExpiration="true"></forms>
</authentication>
<authorization>
  <deny users="?" />
</authorization>
jwalkerjr
sumber
Ini adalah solusi yang lebih sederhana, saya akan menandai ini sebagai jawaban. Karena saya mendapat satu versi kode yang bekerja pada server yang berbeda pada satu saya tidak perlu mengatur properti tambahan yang Anda tambahkan di sini dan yang lain saya lakukan. Jadi memodifikasi kode bukanlah solusi yang tepat, memodifikasi konfigurasi lebih baik.
Vladimir Bozic
Secara default slidingExpiration diatur ke true ( msdn.microsoft.com/library/1d3t3c61(v=vs.100).aspx ). Dan ini akhirnya akan mengakibatkan cookie menjadi tidak valid setelah x menit sebagaimana diatur dalam batas waktu - dan bukan ketika pengguna keluar melalui SignOut (). Jadi ini tidak akan menghasilkan perilaku yang diinginkan untuk mengeluarkan pengguna menggunakan FormsAuthentication. Tolong koreksi saya jika saya salah.
OlafW
12

Kuncinya di sini adalah Anda mengatakan "Jika saya mengetikkan URL secara langsung ...".

Secara default di bawah formulir otentikasi browser cache halaman untuk pengguna. Jadi, memilih URL langsung dari dropdown kotak alamat browser, atau mengetiknya, MUNGKIN mendapatkan halaman dari cache browser, dan tidak pernah kembali ke server untuk memeriksa otentikasi / otorisasi. Solusi untuk ini adalah untuk mencegah caching sisi klien dalam acara Page_Load setiap halaman, atau di OnLoad () dari halaman dasar Anda:

Response.Cache.SetCacheability(HttpCacheability.NoCache);

Anda mungkin juga ingin menelepon:

Response.Cache.SetNoStore();
Phil Haselden
sumber
11

Saya telah berjuang dengan ini sebelumnya juga.

Berikut ini analogi dengan apa yang tampaknya terjadi ... Pengunjung baru, Joe, datang ke situs tersebut dan masuk melalui halaman login menggunakan FormsAuthentication. ASP.NET menghasilkan identitas baru untuk Joe, dan memberinya cookie. Cookie itu seperti kunci rumah, dan selama Joe kembali dengan kunci itu, ia dapat membuka kunci. Setiap pengunjung diberikan kunci baru dan kunci baru untuk digunakan.

Kapan FormsAuthentication.SignOut() dipanggil, sistem memberitahu Joe kehilangan kunci. Biasanya, ini berhasil, karena Joe tidak lagi memiliki kunci, dia tidak bisa masuk.

Namun, jika Joe pernah kembali, dan melakukannya memiliki kunci yang hilang itu, ia akan masuk kembali!

Dari apa yang saya tahu, tidak ada cara untuk memberitahu ASP.NET untuk mengubah kunci di pintu!

Cara saya dapat hidup dengan ini adalah mengingat nama Joe dalam variabel Sesi. Ketika dia logout, saya meninggalkan Sesi jadi saya tidak memiliki namanya lagi. Kemudian, untuk memeriksa apakah dia diizinkan masuk, saya hanya membandingkan Identitasnya. Nama dengan apa yang dimiliki sesi saat ini, dan jika mereka tidak cocok, dia bukan pengunjung yang valid.

Singkatnya, untuk situs web, JANGAN mengandalkan User.Identity.IsAuthenticatedtanpa juga memeriksa variabel Sesi Anda!

Glen Little
sumber
8
+1, saya pikir ini disebut 'Serangan replay cookie'. Ada artikel tentang batasan FormsAuthentication.SignOut: support.microsoft.com/kb/900111
Dmitry
3
Bagi siapa pun yang ingin mengikuti tautan di atas, itu sudah mati. Anda dapat mencoba menggunakan WaybackMachine untuk mendapatkan salinan halaman ini di sini, tetapi SEGERA mencoba untuk mengarahkan pengguna. web.archive.org/web/20171128133421/https://…
killa-byte
7

Setelah banyak pencarian akhirnya ini berhasil untuk saya. Saya harap ini membantu.

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>
Khosro.Pakmanesh
sumber
Saya telah mengembangkan aplikasi web selama bertahun-tahun di PHP. Jadi saya baru mengenal MVC ... Saya akui saya menyukainya, TETAPI siapa yang akan berpikir sesuatu yang sederhana seperti mengeluarkan seseorang akan sangat sulit? Saya mencoba setiap skrip lain pada halaman ini di telepon dan ini adalah satu-satunya yang berhasil. Terima kasih untuk posting!
Anthony Griggs
6

Ini bekerja untuk saya

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());
    }
Korayem
sumber
3

Kode yang Anda poskan sepertinya harus dengan benar menghapus token autentikasi bentuk, sehingga ada kemungkinan folder / halaman tersebut tidak benar-benar dilindungi.

Sudahkah Anda mengonfirmasi bahwa halaman tidak dapat diakses sebelum login telah terjadi?

Bisakah Anda memposting pengaturan web.config dan kode masuk yang Anda gunakan?

Abram Simon
sumber
3

Saya telah menulis kelas dasar untuk semua Halaman saya dan saya sampai pada masalah yang sama. Saya memiliki kode seperti berikut ini dan tidak berfungsi. Dengan menelusuri, kontrol melewati dari pernyataan RedirectToLoginPage () ke baris berikutnya tanpa harus diarahkan.

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

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

Saya menemukan bahwa ada dua solusi. Entah untuk mengubah FormsAuthentication.RedirectToLoginPage (); menjadi

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

ATAU untuk memodifikasi web.config dengan menambahkan

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

Dalam kasus kedua, saat melacak, kontrol tidak mencapai halaman yang diminta. Ini telah dialihkan segera ke url login sebelum mengenai break point. Oleh karena itu, metode SignOut () bukan masalah, metode redirect adalah satu.

Saya harap itu dapat membantu seseorang

Salam

Wahid Shalaly
sumber
2
Anda juga dapat menghubungi Response.End () hanya setelah memanggil FormsAuthentication.RedirectToLoginPage ()
murki
Saya pikir ada sedikit miskomunikasi di pihak MS. Anda harus mengunci orang keluar jika Anda ingin mereka kembali ke halaman login. Kalau tidak, kerangka kerja akan dengan senang hati memungkinkan Anda mengakses. Jadi, Anda harus mengatakan solusi # 2 dalam posting ini.
Josh Robinson
3

Saya baru saja mencoba beberapa saran di sini dan sementara saya bisa menggunakan tombol kembali browser, ketika saya mengklik pilihan menu token [Otorisasi] untuk [ActionResult] mengirim saya kembali ke layar login.

Ini kode logout saya:

        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);
        }

Meskipun fungsi kembali pada browser membawa saya kembali dan menampilkan menu aman (saya masih mengerjakannya), saya tidak dapat melakukan apa pun yang diamankan dalam aplikasi.

Semoga ini membantu

DonH
sumber
Terima kasih. Ini adalah solusi yang bekerja untuk saya (tidak perlu <deny users="?" />di web.config)
Alexei
3

Saya sudah mencoba sebagian besar jawaban di utas ini, tidak berhasil. Berakhir dengan ini:

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();
}

Ditemukan di sini: http://forums.asp.net/t/1306526.aspx/1

stoffen
sumber
3

Jawaban ini secara teknis identik dengan Khosro.Pakmanesh. Saya mempostingnya untuk mengklarifikasi bagaimana jawabannya berbeda dari jawaban lain di utas ini, dan di mana use case dapat digunakan.

Secara umum untuk menghapus sesi pengguna, lakukan

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

secara efektif akan mengeluarkan pengguna. Namun , jika dalam Permintaan yang sama Anda perlu memeriksa Request.isAuthenticated(seperti yang sering terjadi dalam Filter Otorisasi, misalnya), maka Anda akan menemukan bahwa

Request.isAuthenticated == true

bahkan _setelah kamu lakukan HttpContext.Session.Abandon()danFormsAuthentication.SignOut() .

Satu-satunya hal yang berhasil adalah melakukannya

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

Itu secara efektif ditetapkan Request.isAuthenticated = false.

seebiscuit
sumber
2

Ini mulai terjadi pada saya ketika saya mengatur otentikasi> formulir> Path properti di Web.config. Menghapus yang memperbaiki masalah, dan FormsAuthentication.SignOut();cookie yang sederhana dihapus lagi.

BPM
sumber
1

Bisa jadi Anda masuk dari satu subdomain (sub1.domain.com) dan kemudian mencoba keluar dari subdomain lain (www.domain.com).

jorsh1
sumber
1

Saya baru saja mengalami masalah yang sama, di mana SignOut () tampaknya gagal menghapus tiket dengan benar. Tetapi hanya dalam kasus tertentu, di mana beberapa logika lain menyebabkan pengalihan. Setelah saya menghapus pengalihan kedua ini (menggantinya dengan pesan kesalahan), masalahnya hilang.

Masalahnya pasti bahwa halaman dialihkan pada waktu yang salah, karenanya tidak memicu otentikasi.

Peder Skou
sumber
1

Saya memiliki masalah yang sama sekarang dan saya percaya masalah dalam kasus saya serta poster aslinya adalah karena pengalihan. Secara default, Response.Redirect menyebabkan pengecualian yang segera muncul hingga ditangkap dan pengalihan segera dieksekusi, saya menduga ini mencegah pengumpulan cookie yang dimodifikasi agar tidak diturunkan ke klien. Jika Anda memodifikasi kode Anda untuk digunakan:

Response.Redirect("url", false);

Ini mencegah pengecualian dan tampaknya memungkinkan cookie dikirim dengan benar ke klien.

batu yang hilang
sumber
1

Cobalah mengirim variabel sesi ketika Anda menekan masuk. Dan pada halaman pembuka, periksa dulu apakah sesi itu kosong seperti ini di halaman yang dimuat atau di Acara Init:

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

Bagi saya, pendekatan berikut ini berhasil. Saya pikir jika ada kesalahan setelah pernyataan "FormsAuthentication.SignOut ()", SingOut tidak berfungsi.

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

            return Redirect("~/");
        }
        return View();
     }
Aji
sumber
0

Apakah Anda menguji / melihat perilaku ini menggunakan IE? Mungkin saja IE menyajikan halaman-halaman itu dari cache. Sangat sulit untuk membuat IE mem-flush cache-nya, dan pada banyak kesempatan, bahkan setelah Anda logout, mengetik url salah satu halaman "aman" akan menampilkan konten yang di-cache dari sebelumnya.

(Saya telah melihat perilaku ini bahkan ketika Anda masuk sebagai pengguna yang berbeda, dan IE menunjukkan bilah "Selamat Datang" di bagian atas halaman Anda, dengan nama pengguna pengguna yang lama. Saat ini, biasanya sebuah reload akan memperbaruinya, tetapi jika tetap , itu masih bisa menjadi masalah caching.)

Stobor
sumber
0

Melakukan Session.abandon () dan menghancurkan cookie berfungsi cukup baik. Saya menggunakan mvc3 dan sepertinya masalah terjadi jika Anda pergi ke halaman yang dilindungi, logout, dan pergi melalui riwayat browser Anda. Bukan masalah besar tapi masih agak menyebalkan.

Namun, mencoba menelusuri tautan di aplikasi web saya berfungsi dengan benar.

Menyetelnya untuk tidak melakukan caching browser mungkin merupakan cara yang harus dilakukan.

James
sumber
0

Untuk MVC ini bekerja untuk saya:

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

Saya ingin menambahkan beberapa informasi untuk membantu memahami masalahnya. Formulir Otentikasi memungkinkan untuk menyimpan data pengguna baik dalam cookie, atau dalam string kueri URL. Metode yang didukung situs Anda dapat dikonfigurasi dalam file web.config.

Menurut Microsoft :

Metode SignOut menghapus informasi tiket bentuk-otentikasi dari cookie atau URL jika CookiesSupported palsu .

Pada saat yang sama, mereka berkata :

Salah satu nilai HttpCookieMode yang menunjukkan apakah aplikasi dikonfigurasikan untuk autentikasi formulir tanpa masak. The default adalah UseDeviceProfile .

Terakhir, tentang UseDeviceProfile, mereka mengatakan :

Jika properti CookieMode diatur ke UseDeviceProfile, properti CookiesSupported akan mengembalikan true jika Browser untuk Permintaan saat ini mendukung kedua cookie dan mengarahkan ulang dengan cookie ; jika tidak, properti CookiesSupported akan mengembalikan false.

Menyatukan semua ini bersama-sama, tergantung pada browser pengguna, konfigurasi default dapat mengakibatkan CookiesSupported menjadi benar , yang berarti metode SignOut tidak menghapus tiket dari cookie. Ini tampaknya kontra-intuitif dan saya tidak tahu mengapa ia bekerja seperti ini - saya harapkan SignOut untuk benar-benar mengeluarkan pengguna dalam keadaan apa pun.

Salah satu cara untuk membuat SignOut bekerja dengan sendirinya adalah mengubah mode cookie menjadi "UseCookies" (yaitu cookie diperlukan) di file web.config:

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

Menurut pengujian saya, melakukan ini membuat SignOut bekerja dengan sendirinya dengan biaya situs Anda sekarang yang membutuhkan cookie untuk berfungsi dengan baik.

RogerMKE
sumber
Saya pikir Anda salah membaca. Mengenai SignOut (), saya cukup yakin apa yang mereka maksud adalah bahwa itu akan dihapus dari URL jika CookiesSupported salah, jika tidak dari cookie. Yaitu mereka seharusnya menulis "Metode SignOut menghapus informasi tiket bentuk-otentikasi dari cookie atau, jika CookiesSupported salah, dari URL."
Oskar Berggren
-1

Ketahuilah bahwa WIF menolak memberitahu browser untuk membersihkan cookie jika pesan wsignoutcleanup dari STS tidak cocok dengan url dengan nama aplikasi dari IIS, dan maksud saya KASUS SENSITIF . WIF merespons dengan tanda centang OK hijau, tetapi tidak akan mengirim perintah untuk menghapus cookie ke browser.

Jadi, Anda perlu memperhatikan sensitivitas huruf url Anda.

Sebagai contoh, ThinkTecture Identity Server menyimpan url dari RP yang dikunjungi dalam satu cookie, tetapi itu membuat semuanya lebih kecil. WIF akan menerima pesan wsignoutcleanup dalam huruf kecil dan akan membandingkannya dengan nama aplikasi di IIS. Jika tidak cocok, itu tidak menghapus cookie, tetapi akan melaporkan OK ke browser. Jadi, untuk Server Identitas ini saya perlu menulis semua url di web.config dan semua nama aplikasi di IIS dalam huruf kecil, untuk menghindari masalah seperti itu.

Juga jangan lupa untuk mengizinkan cookie pihak ketiga di peramban jika Anda memiliki aplikasi di luar subdomain STS, jika tidak peramban tidak akan menghapus cookie meskipun WIF memberitahunya.

Stefan
sumber
1
WIF? STS? ThinkTecture Identity Server? Apa semua hal ini, dan bagaimana mereka berhubungan dengan pertanyaan ini?
Oskar Berggren