none
การ Log Out จากหน้า ASP.Net โดยใช้ asp:LoginStatus และทำให้ไม่สามารถเรียกดูหน้าย้อนหลัง ผ่านทาง Page History ของ Client Browser ได้ RRS feed

  • คำถาม

  • เนื่องจากผมได้พัฒนา Web Application ขึ้นมาตัวหนึ่ง แต่ติดที่เมื่อเวลา Log out ออกไปแล้ว หากมีการกดเรียกดูจาก History ที่หน้า Browser ของ Client

    หน้า Page นั้น ๆ ยังแสดงข้อมูลที่ Browser ได้ Cache ไว้อยู่

    ไม่ทราบว่ามีวิธีไหนบ้าง ที่จะมำให้ ไม่สามารถเรียกดูหน้า page เก่าจาก History ได้ครับ เช่น มี Script ที่ตรวจสอบว่าได้ Logout แล้ว ไม่สามารถเปิดดูได้ หรือ Script ที่บังคับให้ Page ต้อง Check กับ Server เสมอ ว่ายังไม่ Membership Expired หรือ Page  Expired โดยทั้งหมดต้อง Run ที่ Client เนื่องจาก เมื่อกดปุ่ม back หรือ History ไม่ได้ เกิด Event Page_Load ใหม่ที่ Server

     

    ข้อมูล เพิ่มเติม

    1. ผมได้ทดลองใช้วิธีดังต่อไปนี้แล้ว ไม่ได้ผล คือ

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

    Response.Cache.SetCacheability(HttpCacheability.NoCache);
    Response.Cache.SetCacheability(HttpCacheability.Private);

    Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(-1));
    Response.Cache.SetCacheability(HttpCacheability.NoCache);
    Response.Cache.SetNoStore();
    Response.AppendHeader("Pragma", "no-cache");
    Response.AppendHeader("Cache-Control", "no-cache");
    Response.AppendHeader("Cache-Control", "no-store");
    Response.CacheControl = "no-cache";

     

    2. วิธีที่ป้องกันการกดปุ่ม Back บน browser โดยใช้ javascript ไม่ได้ผล เนื่องจาก สามารถเรียกจาก History ได้

     

    3. พอดีเห็น Code PHP ที่ป้องกัน การเรียก Page ใน history แล้วได้ผล อาจจะเป็นแนวทางได้ แต่ไม่ทราบว่าทำงานเช่นไร

    if(!session_is_registered("globalusername"))
            {
                echo "<meta http-equiv='refresh' content='1; URL=login.php'>";
                exit;
            }

     

    .....

     

     

     

    5 มกราคม 2554 10:41

คำตอบ

  • สวัสดีค่ะ คุณ Kikapooz

    ลองทำตาม demo นี้นะคะ ประมาณ 2 หน้า

    หน้าแรก คือ หน้า Login page เอาไว้เรียก Login.aspx และอีกหน้า คือ หน้าที่เอาไว้เรียก Home.aspx
    ส่วน
    default password สำหรับการ Login คือ admin
    ทั้งหมดนี้ ใช้ภาษา
    C# ค่ะ

    Code of Login.aspx.

    <%@ Page Language="C#" %>

    <!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 btnLogin_Click(object sender, EventArgs e)

        {  

            // the defaut password is "admin".

            if (txtPswd.Text == "admin")

            {

                Session["isLogin"] = true;

                Response.Redirect("Home.aspx");

            }

            else

            {

                Response.Write("Your password is not correct.");

                txtPswd.Text = "";

            }

        }

    </script>

     

    <html xmlns="http://www.w3.org/1999/xhtml">

    <head runat="server">

        <title></title>

    </head>

    <body>

        <form id="form1" runat="server">

        <div>

            Password:

            <asp:TextBox ID="txtPswd" runat="server"></asp:TextBox>

            <asp:Button ID="btnLogin" runat="server" Text="Login" onclick="btnLogin_Click" />

        </div>

        </form>

    </body>

    </html>

     

    Code of Home.aspx.

    <%@ Page Language="C#" %>

    <!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)

        {

            Response.AppendHeader("Cache-Control", "no-store");

           

            // check if Session is existed.

            if (Session["isLogin"] == null)

            {

                Response.Redirect("Login.aspx");

            }

           

            // check is user has logged in.

            if ((bool)Session["isLogin"] == false)

            {

                Response.Redirect("Login.aspx");

            }

           

            Response.Write(DateTime.Now.ToLongTimeString());

        }

     

        protected void btnLogout_Click(object sender, EventArgs e)

        {

            // logout.

            Session.Abandon();

            Response.Redirect("Login.aspx");

        }

    </script>

     

    <html xmlns="http://www.w3.org/1999/xhtml">

    <head runat="server">

        <title></title>

    </head>

    <body>

        <form id="form1" runat="server">

        <div>

            <asp:Button ID="btnLogout" runat="server" Text="Logout"

                onclick="btnLogout_Click" />

        </div>

        </form>

    </body>

    </html>

     

    แต่ถ้าอยากใช้ JavaScript ก็ลองใช้ code นี้ดู

    <script type="text/javascript">

        window.onload = function() {

            history.go(1);

        }

    </script>

    มันจะบังคับ หน้า page ให้ไปที่หน้าต่อไปเลย สำหรับใน browser history list ทีนี้คนอื่นก็จะดู  history ผ่านทางปุ่ม Back บน browser ไม่ได้แล้ว

    ส่วน code PHP ที่คุณหามาได้ มีความหมายเดียวกับ code C# อันนี้ค่ะ

    if (!session_is_registered("globalusername"))

    {

        Response.Write("<meta http-equiv='refresh' content='1; URL=login.php'>");

        return;

    }

    ก็คือ เราสามารถใช้ function session_is_registered()ตรวจสอบได้เวลามีคน log in เข้ามา
    หรือว่าจะใช้
    meta tag เพื่อให้มัน redirect กลับไปที่หน้า login.php  ก็ได้ค่ะ
    ถ้ายังไงก็ ดูข้อมูลเพิ่มเติมได้ที่
    http://en.wikipedia.org/wiki/Meta_refresh


    Supa Sethasiripong [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • เสนอเป็นคำตอบโดย supa_sModerator 13 มกราคม 2554 5:22
    • ทำเครื่องหมายเป็นคำตอบโดย Sirikhun TriwittayakhunModerator 11 พฤษภาคม 2554 1:47
    6 มกราคม 2554 9:34
    ผู้ดูแล

ตอบทั้งหมด

  • สวัสดีค่ะ คุณ Kikapooz

    ลองทำตาม demo นี้นะคะ ประมาณ 2 หน้า

    หน้าแรก คือ หน้า Login page เอาไว้เรียก Login.aspx และอีกหน้า คือ หน้าที่เอาไว้เรียก Home.aspx
    ส่วน
    default password สำหรับการ Login คือ admin
    ทั้งหมดนี้ ใช้ภาษา
    C# ค่ะ

    Code of Login.aspx.

    <%@ Page Language="C#" %>

    <!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 btnLogin_Click(object sender, EventArgs e)

        {  

            // the defaut password is "admin".

            if (txtPswd.Text == "admin")

            {

                Session["isLogin"] = true;

                Response.Redirect("Home.aspx");

            }

            else

            {

                Response.Write("Your password is not correct.");

                txtPswd.Text = "";

            }

        }

    </script>

     

    <html xmlns="http://www.w3.org/1999/xhtml">

    <head runat="server">

        <title></title>

    </head>

    <body>

        <form id="form1" runat="server">

        <div>

            Password:

            <asp:TextBox ID="txtPswd" runat="server"></asp:TextBox>

            <asp:Button ID="btnLogin" runat="server" Text="Login" onclick="btnLogin_Click" />

        </div>

        </form>

    </body>

    </html>

     

    Code of Home.aspx.

    <%@ Page Language="C#" %>

    <!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)

        {

            Response.AppendHeader("Cache-Control", "no-store");

           

            // check if Session is existed.

            if (Session["isLogin"] == null)

            {

                Response.Redirect("Login.aspx");

            }

           

            // check is user has logged in.

            if ((bool)Session["isLogin"] == false)

            {

                Response.Redirect("Login.aspx");

            }

           

            Response.Write(DateTime.Now.ToLongTimeString());

        }

     

        protected void btnLogout_Click(object sender, EventArgs e)

        {

            // logout.

            Session.Abandon();

            Response.Redirect("Login.aspx");

        }

    </script>

     

    <html xmlns="http://www.w3.org/1999/xhtml">

    <head runat="server">

        <title></title>

    </head>

    <body>

        <form id="form1" runat="server">

        <div>

            <asp:Button ID="btnLogout" runat="server" Text="Logout"

                onclick="btnLogout_Click" />

        </div>

        </form>

    </body>

    </html>

     

    แต่ถ้าอยากใช้ JavaScript ก็ลองใช้ code นี้ดู

    <script type="text/javascript">

        window.onload = function() {

            history.go(1);

        }

    </script>

    มันจะบังคับ หน้า page ให้ไปที่หน้าต่อไปเลย สำหรับใน browser history list ทีนี้คนอื่นก็จะดู  history ผ่านทางปุ่ม Back บน browser ไม่ได้แล้ว

    ส่วน code PHP ที่คุณหามาได้ มีความหมายเดียวกับ code C# อันนี้ค่ะ

    if (!session_is_registered("globalusername"))

    {

        Response.Write("<meta http-equiv='refresh' content='1; URL=login.php'>");

        return;

    }

    ก็คือ เราสามารถใช้ function session_is_registered()ตรวจสอบได้เวลามีคน log in เข้ามา
    หรือว่าจะใช้
    meta tag เพื่อให้มัน redirect กลับไปที่หน้า login.php  ก็ได้ค่ะ
    ถ้ายังไงก็ ดูข้อมูลเพิ่มเติมได้ที่
    http://en.wikipedia.org/wiki/Meta_refresh


    Supa Sethasiripong [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • เสนอเป็นคำตอบโดย supa_sModerator 13 มกราคม 2554 5:22
    • ทำเครื่องหมายเป็นคำตอบโดย Sirikhun TriwittayakhunModerator 11 พฤษภาคม 2554 1:47
    6 มกราคม 2554 9:34
    ผู้ดูแล
  • โอ้ว ได้ผลดีเยิ่ยมเลยครับขอบคุณมาก

     

    ข้อมูลเพิ่มเติม สำหรับผู้จะไปใช้ต่อนะครับ

    1.  สำหรับผม ใช้ asp:Login Control เป็นตัวกำหนดการเข้าใช้งาน Code ดังนั้นในส่วนของ Session["isLogin"] สามารถนำไปใส่ในหน้า Login.aspx ในส่วนดังนี้

            protected void Login1_LoggedIn(object sender, EventArgs e)
            {
                Session["isLogin"] = true;
            }

    โดยกำหนด Event ที่ LoggedIn ของ ASP:Login Control ในหน้า Properties ของ Design View ได้เลย

    2. หากใช้ Master Page สามารถนำ Code ในส่วนของ Page_Load และ btnLogout_Click ไปไว้ใน Master Page ได้เลย

    3. หากใช้ asp:LoginStatus Control เป็นตัว Logout สามารถนำส่วน  Session.Abandon(); ไปไว้ในส่วนของ

            protected void LoginStatus1_LoggedOut(object sender, EventArgs e)
            {
                Session.Abandon();
            }

    โดยกำหนด Event ที่ Loggedฯีะ ของ ASP:LoginStatus Control ในหน้า Properties ของ Design View ได้เลยเช่นกัน

    4. สาเหตุสำคัญที่ทำให้สามารถป้องกันได้คือบรรทัด Response.AppendHeader("Cache-Control" , "no-store" ); โดยต้องใส่ทุกหน้าที่ต้องการไม่ให้ย้อนกลับมาดูได้

     

    ปล. ยังไงก็ขอขอบคุณคุณ Supa และ Microsoft อีกครั้งนะครับ เพราะเดี๋ยวคงมีคำถามมาให้ปวดหัวอีกแน่ ๆ . . . และแล้วก็มีจนได้ 
    6 มกราคม 2554 16:26
  • ปัญหาคือดังนี้ครับ

    จากการที่ใส่ Response.AppendHeader("Cache-Control" , "no-store" );    เข้าไปในหน้า Page (ในกรณีนี้คือ Master Page) ทำให้เกิดปัญหาคือ

    เมื่อกดปุ่ม Back ที่ Browser ขณะใช้งาน Web Application อยู่นั้น (Login) ไม่สามารถทำได้ เนื่องจาก จะเกิดปัญหา   

    Webpage has expired

     โดยเฉพาะในหน้าที่มี Control อยู่มาก และมีการ PostBack กลับไปที่หน้าเดิม (ต้องอาศัย ViewState หรือ Session เพื่ออ่านค่าของ Control ในหน้าเดียวกัน เช่น มี Dropdown ของปี ซึ่ง AutoPostBack และเมื่อเปลี่ยนปีแล้ว ข้อมูลรายการใน Listview ก็มีการเปลี่ยน โดยคอนโทรลทั้งคู่อยู่ใน Page เดียวกัน) ก่อน Link ไปหน้าอื่น  (เช่นจาก Page1 ไป Page2) ทำให้ต้องกด refresh เพื่อทำการ load หน้า Page1 ใหม่ หากใช้ปุ่ม back กลับมาเพื่อดูข้อมูลเดิม

    คำถามคือ

    1. ทำอย่างไรให้สามารถกด Back ใน Browser ได้ครับ โดย Page ไม่ Expired

    2. เป็นไปได้ไหม ที่วิธีแก้ในข้อ1 จะทำให้ Control เดิมใน Page เก่าจำ State ของตัวเองได้ (เช่น Dropdown ที่เลือกปี ยังจำได้ว่าเลือกปีอะไร) แต่ถ้าไม่ได้ก็ไม่เป็นไรครับข้อนี้

    ปล. - ขอไม่ใช้วิธี ให้ Disable Back Button โดยใช้ JavaScript นะครับ เพราะ User ชอบกดปุ่ม Back ผมก็ยังชอบเลย ;)

          - ผมได้สังเกตุใน Code ที่เคยเขียน ว่าเคยได้ใส่ Response.Cache.SetCacheability(HttpCacheability.NoCache);  ลงไปแล้ว ซึ่งให้ผลคล้าย ๆ Response.AppendHeader("Cache-Control" , "no-store" );   แต่ได้ Comment ออกไป เนื่องจากเกิด ปัญหา Webpage has expired นั่นเอง  ถึงแม้ว่าจะช่วยแก้ปัญหา Log Out แล้ว ย้อนกลับมาดูข้อมูลเดิมไม่ได้ก็ตาม

    ขอบคุณครับ

     

    • แก้ไขโดย Kikapooz 9 มกราคม 2554 10:17
    6 มกราคม 2554 16:41
  • มาเพิ่มเติมข้อมูลให้ครับ พอดีไปดู Application ที่ย้อนกลับไปดูข้อมูลในหน้าเดิมได้ ในขณะที่ยัง Log in อยู่ พบว่า เป็นวิธีการกำหนด Cache ที่ Client Browser ให้เป็น NoCache ดังที่ คุณ Supa ได้ตอบไว้ในขั้นต้นนั้นเอง 

    เพียงแต่เมื่อมีการเรียกกลับไปที่ page เดิม ผ่านปุ่ม back พบว่า มีการเรียกกลับไปที่ Server ทุกครั้ง เพื่อเรียก Cache ที่ Server

    และใน ASP.Net เอง ก็มีคำสั้ง Response.Cache.SetCacheability(HttpCacheability.ServerAndNoCache); อยู่ด้วย

    เพียงแต่ตอนนี้ ปัญหาที่พบคือ เมื่อกดปุ่ม Back แล้ว ไม่มีการเรียกกลับไปที่ Server เลยอยากทราบว่าต้องทำเช่นไร ตามคำถามข้อข้างบน

     

    ขอบคุณครับ

    9 มกราคม 2554 10:15
  • ก่อนอื่น ต้องขออธิบายก่อนว่า Response.AppendHeader ("Cache-Control", "no-store"); ทำงานอย่างไร

    เมื่อเราคลิกปุ่ม back เบราว์เซอร์จะพยายามหา cache  ของหน้าก่อนหน้านี้ตาม URL เมื่อเบราว์เซอร์พบ cache แล้ว มันก็จะโชว์หน้าเพจให้เรา โดยที่ไม่ต้องไป connect กับ website  แต่ถ้าเบราว์เซอร์หา cache ไม่เจอ มันก็จะ request ไปที่ URL เพื่อ download หน้าเพจนั้นจาก website  สำหรับคำตอบของคำถามก็คือ ให้ code ไป force ให้ browser ไม่ไปที่ cache ของหน้าเพจ เพราะฉะนั้นเวลาที่เราคลิกปุ่ม back  เบราว์เซอร์จะ request หน้าเพจจาก website เสมอ

    สำหรับ demo code ที่ให้ไปก่อนหน้านี้ การทำงานของมัน คือ เมื่อเรา log out และต้องการที่จะกลับไปยังหน้า Home.aspx เบราว์เซอร์จะส่ง new request ไปที่ URLhttp://localhost:xxxx/Website1/Page1.aspx เวลาที่ Page1.aspx กำลังโหลด มันจะเช็ค flag Session[“isLogin”] และ detect ว่าเราได้ log out รึยัง เพราะถ้า log out แล้ว มันก็จะกลับไปที่หน้า Login.aspx แต่ถ้ายัง มันก็จะแสดงหน้า Page1.aspx

    แต่ถ้าเราใช้คำสั่ง AutoPostBack ในการ control หน้าเพจ ปัญหาก็จะซับซ้อนขึ้น เพราะว่า เมื่อเราใช้ AutoPostBack เอาไป set DropDownList หน้าเพจเปลี่ยน แต่ URLไม่ได้เปลี่ยน เพราะฉะนั้นเวลาที่เราคลิกปุ่ม back และ browser พยายามที่จะ request URL มันกลับไม่รู้ว่าหน้าเพจจริงๆนั้นได้เปลี่ยนไปแล้ว ก็เหมือนกับในกรณีของ year DropDownList

    เพื่อที่จะแก้ปัญหานี้ ขอแนะนำให้ใช้ GET method ค่ะ เพื่อ post หน้าpage form
    ส่วน code ก็สามารถเอาไปใช้ได้เลยค่ะ

    Code of Home.aspx.

    <%@ Page Language="C#" %>

     

    <!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)

        {

            Response.AppendHeader("Cache-Control", "no-store");

     

            if (Session["isLogin"] == null)

            {

                Response.Redirect("Login.aspx");

            }

            if ((bool)Session["isLogin"] == false)

            {

                Response.Redirect("Login.aspx");

            }

        }

     

        protected void btnLogout_Click(object sender, EventArgs e)

        {

            Session.Abandon();

            Response.Redirect("Login.aspx");

        }

    </script>

     

    <html xmlns="http://www.w3.org/1999/xhtml">

    <head runat="server">

        <title></title>

    </head>

    <body>

        <form id="form1" runat="server" method="get">

        <div>

            <asp:DropDownList ID="ddlYear" runat="server" AutoPostBack="true">

                <asp:ListItem>2008</asp:ListItem>

                <asp:ListItem>2009</asp:ListItem>

                <asp:ListItem>2010</asp:ListItem>

            </asp:DropDownList>

            <asp:Button ID="btnLogout" runat="server" Text="Logout" OnClick="btnLogout_Click" />

        </div>

        </form>

    </body>

    </html>

     

    แต่ถ้ายังมีอะไรไม่เข้าใจหรือสงสัยตรงไหน ก็ถามได้นะคะ


    Supa Sethasiripong [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • เสนอเป็นคำตอบโดย supa_sModerator 13 มกราคม 2554 5:22
    12 มกราคม 2554 5:57
    ผู้ดูแล
  • ขอบคุณมากครับ

     

    พอดีไปค้นดูใน Internet ก็พบคำตอบ เช่นเดียวกับที่คุณ Supa ได้มาตอบไว้ คือ ให้ใช้ method Get ที่ tag form นั่นเอง ( กว่าจะเจอ เกือบจะท้อซะแล้ว อิ อิ )

    และอย่าลืมกำหนดค่า ใน Web.Cofig ในส่วนของค่า maxQueryStringLength เพื่อให้ Web Application สามารถรับ QueryString ได้ยาวขึ้น ดังตัวอย่าง (สามารถลองเพิ่มได้ มากกว่า 2048 ตามสมควร)

    <configuration>

        <system.web>

    <httpRuntime maxQueryStringLength="2048" />

    และนอกจากนี้ หากใครไม่ต้องการให้ URL ดูยาวเกินไป สามารถใช้ iframe ครอบได้ เช่นกัน

     

    ยังไงหากมีข้อสงสัยในเรื่องอื่น คงต้องขอรบกวนใหม่นะครับ

     

    12 มกราคม 2554 15:57
  • สวัสดีครับ ผมมือใหม่ เจอบทความนี้ ก็ช่วยผมได้เยอะครับ แต่ผมมีข้อสงสัยคือ ตอนนี้ ปุ่ม back ผมทำได้แล้ว แต่ history  ยังคงเข้าได้อ่ะครับ พอจะมีแนวทางอย่างไรบ้างครับ 

    ผมทำหน้าlog in ตามเว็บนี้ครับ แต่มันก้ไม่ยอมเคลียร์ cookie สักทีนึง รบกวนด้วยครับ  ขอบคุณครับ

     

    http://www.codetoday.net/default.aspx?g=posts&t=1068

    26 มกราคม 2554 9:23
  • เข้าได้ นี่หมายถึง พอเลือกใน History แล้ว ยังแสดงผลเดิมอยู่ใช่ไหมครับ ลองตรวจดูตามขั้นตอน ดังนี้ละกัน

     

    1. ได้ทำ ASP.Net Membership แล้วหรือยัง

    2. หากทำแล้ว กำหนด สิทธิการเข้าถึง Folder ใน ASP.Net Configuration ส่วนของ Security แล้วหรือยัง

    3. กำหนด ให้ Client Browser ไม่ให้มีการ Caching หน้า Page ตาม Reply ข้างบน แล้วหรือยัง

     

    ยังไงลองตรวจสอบ 3 ข้อนี่ก่อน ว่าลืมตรงไหนละกันครับ

     

    27 มกราคม 2554 10:13