不拖控件ASP.NET——探知cookie和session(2)

    接着上篇的博客我们来讲解服务器端保存数据的机制—session

    我们知道cookie是保存在客户端的,这样数据就存在一个不安全性,此外还有 一个问题就是不能够存储大量的数据,我们上篇博客还遗留一个问题就是客户端是可以篡改数据的,相当于保留在病人手上的病历本是可能被用户篡改的(一般情况下,用户不会篡改,这样多危险了,医生误诊怎么办?哈哈)

    此外医生会给每个患者编制一个编号,并且自己再保存一个编号,这样当病人来的时候根据编号来识别病人的身份,当然用户会可以别人的编号猜出来自己的编号,那又该怎么办呢?

  1.      自己实现“服务端的cookie”—session

    我们需要一种“服务器端的Cookie”:1、医生需要一个私人账本,记录病人编号和身份的对应关系;2、为了防止病人根据分配给他的编号猜测前后人的编号,那么需要一种“很难猜测的”编码机制。

    如何防止病人来猜测别人的编号:随机数可以,但是不是最好的,因为随机数的生成可能会发生重复,什么是最好的?利用Guid(上篇博客讲解过)来实现,根据网卡编号等等来生成唯一的编号,它是能够保证生成的编号是全球唯一的。   

    那么医生的私人账本存在哪里,我们知道在病人手里不是安全的?答案是可以存在静态变量里面,即静态管理器session。

    那我们来实践一下吧

    ?  示例演示

      这里我们还是采用Nvelocity模板驱动机制进行演示,还是将模板封装在commonHelper类里。这里不再写代码了,前面的已经写过了,详情参考:链接:http://blog.csdn.net/u010955843/article/details/43117097

      之后建立一般处理程序Login

<span style="font-family:Microsoft YaHei;font-size:14px;"><strong>using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace session
{
    /// <summary>
    /// Login 的摘要说明
    /// </summary>
    public class Login : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/html";
            //context.Response.Write("Hello World");
            string login = context.Request["Login"];

            if (string.IsNullOrEmpty(login))
            {
           
                string html = commonHelper.RenderHtml("Login.html", null);
                context.Response.Write(html);
            }
            else
            {
                string username = context.Request["UserName"];
                string password = context.Request["password"];
                if (password == "123456")
                {
                    //context.Response.SetCookie(new HttpCookie("UserName",username));
                    Guid id = Guid.NewGuid(); //生成一个医生分配的用户编号
                    sessionMgr.Jizhang(id, username); //登陆时写进账本

                    //把医生分配的病人编号写进病历本
                    context.Response.SetCookie(new HttpCookie("zhangbenId", id.ToString()));
                    context.Response.Redirect("Test1.ashx");
                }
            }
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}
</strong></span>

      在建立一个一般处理程序Test1来读取cookie并将其进行输出

<span style="font-family:Microsoft YaHei;font-size:14px;"><strong>using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace session
{
    /// <summary>
    /// Test1 的摘要说明
    /// </summary>
    public class Test1 : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/html";
            //context.Response.Write("Hello World");
            HttpCookie cookie = context.Request.Cookies["zhangbenId"];
            if (cookie == null)
            {
                context.Response.Redirect("Login.ashx");
            }
            else
            {
                Guid id = new Guid(cookie.Value);
                if (sessionMgr.IsJizhang(id))
                {
                    string value = sessionMgr.Get(id);
                    context.Response.Write(value);
                }
                else
                {
                    context.Response.Redirect("Login.ashx");
                }

            }
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}</strong></span>

      新建一个类,用于写入一些方法,定义保存、获取cookieid的方法

<span style="font-family:Microsoft YaHei;font-size:14px;"><strong>using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace session
{
    public class sessionMgr
    {
        //字典是一种键值对形式,定义一个Guid的名字,static在.net framework运行的时候一直存在,这样可以在服务器端保存( 医生的账本);并不会因为http请求的消失而消失
        private static Dictionary<Guid, string> zhangben = new Dictionary<Guid, string>();
        //给账本的id赋值
        public static void Jizhang(Guid id, string value)
        {
            zhangben[id] = value;
        }
        //是否记账
        public static bool IsJizhang(Guid id)
        {
            return zhangben.Keys.Contains(id);
        }
        //这里加上static,原因在于http是无状态的,但是生成static,就是在整个framework运行期间能够保存,能够在服务器端保存整个值
        public static string Get(Guid id)
        {
            return zhangben[id];
        }
    }
}</strong></span>

      建立模板引擎的渲染模板HTML页为Login.html(建立一个文件夹templates,html写在文件夹下面,与模板引擎中的位置同步)

<span style="font-family:Microsoft YaHei;font-size:14px;"><strong><!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form action="../Login.ashx" method="post">
        <input  type="text" name="UserName"/>
        <input type="password" name="password" />
        <input type="submit" name="Login" value="登陆" />
    </form>
</body>
</html></strong></span>

      ?  报文解析

      第一次进入程序的时候是没有cookie的,显示界面如下图

技术分享

      此时我们填写登陆用户名和密码(自己之前设置好的,因为此时我只是做个例子,没有建立与数据库的连接,故而写死了一个密码。)这时执行Login程序程序中的else代码,并且写进cookie,报文如下图:

技术分享

      Post中的信息也就是我们输入的信息

技术分享

      之后在Test1.ashx中进行处理,将对相应的cookie值进行判断之后再输出

技术分享

    所谓自己实现的session机制,把数据存到了服务器端,就是存储了一个id;客户端放置的文件有大小的限制,但是服务器端没有这个限制,内存是很大的;当我们再次在同一个浏览器中打开一个新的地址栏并且输入的时候此时仍旧显示输出的cookie,说明这个是保存在服务器端,并且是可以共享的,但是在不同浏览器中就会转向登录界面,说明是不能跨浏览器的,因为ie与火狐的机制不一样。

  2.      Asp.NET内置的session机制

    ASP.Net已经内置了Session机制,把上面的例子用ASP.Netsession重写。普通的HttpHandler要能够操作session,实现IRequiresSessionState接口。读写页面都得实现这个接口,login2是写入session,而test是读session。

 

    ?  示例

      commonHelper以及封装获取、保存SessionId的方法是一样的,并且模板的Html也是一样的,不同是程序程序Login.ashx以及Test1.ashx中的代码的变更。

      Login.ashx

<span style="font-family:Microsoft YaHei;font-size:14px;"><strong>using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.SessionState;

namespace ASP.NETSession
{
    /// <summary>
    /// Login 的摘要说明
    /// </summary>
    /// ASP.NET内置的session必须引进命名空间System.Web.SessionState;也是为了实现IRequiresSessionState接口
    public class Login : IHttpHandler, IRequiresSessionState
    {

        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/html";
            //context.Response.Write("Hello World");
            string login = context.Request["Login"];

            if (string.IsNullOrEmpty(login))
            {
                string html = commonHelper.RenderHtml("Login.html", null);
                context.Response.Write(html);
            }
            else
            {
                string username = context.Request["UserName"];
                string password = context.Request["password"];
                if (password == "123456")
                {
                    //服务器端提供的索引
                    context.Session["yonghuming"] = username;
                    context.Response.Redirect("Test1.ashx");
                }
            }
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}</strong></span>

      Test1.ashx读取SessionId

<span style="font-family:Microsoft YaHei;font-size:14px;"><strong>using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.SessionState;

namespace ASP.NETSession
{
    /// <summary>
    /// Test1 的摘要说明
    /// </summary>
    /// 同理读取cookie的也得实现这个接口IRequiresSessionState
    public class Test1 : IHttpHandler, IRequiresSessionState
    {

        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/html";
            if (context.Session == null)
            {
                context.Response.Redirect("Login.ashx");
            }
            else
            {
                //Session可以存储任何字符型的
                string yonghuming = (string)context.Session["yonghuming"];
                if (string.IsNullOrEmpty(yonghuming))
                {
                    context.Response.Redirect("Login.ashx");
                }
                else
                {
                    context.Response.Write(yonghuming);
                }
            }
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}</strong></span>

    ?  报文解析

      第一次进入程序的时候是没有session的,显示界面如下图

技术分享

      此时我们填写登陆用户名和密码(自己之前设置好的,因为此时我只是做个例子,没有建立与数据库的连接,故而写死了一个密码。)这时执行Login程序程序中的else代码,并且写进session,报文如下图:

技术分享

      Post中的信息也就是我们输入的信息

技术分享

      之后在Test1.ashx中进行处理,将对相应的cookie值进行判断之后再输出

技术分享

      对比我们之前的自己实现的“服务器端的cookie”,发现了什么呢?

  3.      SessionId知多少?

      对比两者我们可以发现其实Session是依赖于cookie的,其内部将其生成一个值,都是往客户端生成了一个id,它是依赖于cookie,只不过是借助于cookie机制让我们可以在服务器端来存储数据,这就是session的原理;session依赖于cookie,依赖于cookie帮它存了一个id。

技术分享

    相当于医生在病历本上写的编号id就是sessionid。对比我们自己实现的“服务器端的cookie”,我们更好理解我们Session的实现机理。

  4.      Session的销毁

      一个互联网,当某个session某个时间段内没有和服务器进行交互的时候,会进行自动销毁,asp.net提供了这样的一个机制。

像医生记账本,当一个病人长时间不来的时候,医生会自己将其时间长的销毁,这样存在一个助理,记录病人的看病记录,某个人来看病了,并且总是记录病人最后一次来看病的记录,把长期不来的病人删除掉,这样能够减少服务器端的压力和内存,提高运行的效能。

      Session(会话)有自动销毁机制,如果一段时间内浏览器没有和服务器发生任何的交互,则Session会定时销毁,这也就是为什么一段时间不操作,系统就会自动退出。

      当你长时间不登陆的时候,当你再次登陆的时候系统提醒重新登录的原因在于session的自动销毁机制。默认时间是30分钟后自动销毁。故而了解session的原理,便于我们很好的利用它。

  5.      总结

    不知道讲的是不是清晰,缓存在我们编写程序中有很重要的应用,学好它便于我们更好地运用它,感兴趣的自己试试吧。




郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。