Thursday, February 9, 2012

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

ลองทำตาม 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>

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

<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

ข้อมูลเพิ่มเติม สำหรับผู้จะไปใช้ต่อนะครับ
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" ); โดยต้องใส่ทุกหน้าที่ต้องการไม่ให้ย้อนกลับมาดูได้

ก่อนอื่น ต้องขออธิบายก่อนว่า 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>

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

พอดีไปค้นดูใน Internet ก็พบคำตอบ เช่นเดียวกับที่คุณ Supa ได้มาตอบไว้ คือ ให้ใช้ method Get ที่ tag form นั่นเอง ( กว่าจะเจอ เกือบจะท้อซะแล้ว อิ อิ )
และอย่าลืมกำหนดค่า ใน Web.Cofig ในส่วนของค่า maxQueryStringLength เพื่อให้ Web Application สามารถรับ QueryString ได้ยาวขึ้น ดังตัวอย่าง (สามารถลองเพิ่มได้ มากกว่า 2048 ตามสมควร)
<configuration>
    <system.web>
<httpRuntime maxQueryStringLength="2048" />
และนอกจากนี้ หากใครไม่ต้องการให้ URL ดูยาวเกินไป สามารถใช้ iframe ครอบได้ เช่นกัน

ref : http://social.msdn.microsoft.com/Forums/th-TH/visualstudioth/thread/f693f996-36e8-497c-a2f6-4d88d38bcdcb/

No comments:

Post a Comment