ASP.NET Cookie和Session
Cookie和Session
C#在服务器,JS在客户端
客户端验证不能代替服务端验证
Http
HTTP属于应用层,HTTP 协议一共有五大特点:1、支持客户/服务器模式;2、简单快速;3、灵活;4、无连接;5、无状态。
无状态
无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
Http协议是无状态的,不会记得上次和网页“发生了什么”。
HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。
1 int i;//放在外面,放在主函数里面,i++会未初始化 2 //每次请求的时候,都会new一个新对象 3 public void ProcessRequest(HttpContext context) 4 { 5 6 context.Response.ContentType = "text/html"; 7 string path = HttpContext.Current.Server.MapPath("~/HtmlPage1.html"); 8 string str = File.ReadAllText(path); 9 string html; 10 if (string.IsNullOrEmpty(context.Request["tj"])) 11 { 12 html = str.Replace("@qq", "0"); 13 i = 2; 14 } 15 else 16 { 17 i++;//int默认值为0,输出1,不会输出2 18 html = str.Replace("@qq", i.ToString()); 19 } 20 context.Response.Write(html);
浏览器需要记住这些值,下次再提交服务器的时候就要把上次的值提交给服务器,让他想起来。如果要知道上一次的状态,一个方法是在对浏览器响应结束之前将状态信息保存到页面表单中,下次页面再向服务器发出请求的时候带上这些状态信息,这样服务器就能根据这些状态信息还原上次的状态了。
无连接
无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
两种用于保持 HTTP 连接状态的技术就应运而生了,一个是 Cookie,一个是Session。
会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。
Cookie
Cookie是通过客户端保持状态的解决方案。
在程序中,会话跟踪是很重要的事情。理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话
给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。
Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
1 context.Response.ContentType = "text/html"; 2 //cookie:键值对 3 HttpCookie cookie1 = context.Request.Cookies["test"]; 4 5 context.Response.Write(cookie1==null?"没有test这个cookie":cookie1.Value);
1 context.Response.ContentType = "text/html"; 2 HttpCookie cookie = new HttpCookie("test"); 3 //cookie.Value = "rupeng.com"; 4 cookie.Value = context.Request.UserAgent; 5 /* 6 cookie.Expires = DateTime.Now.AddDays(20);//DateTime.Now当前时间 7 //DateTime的AddDays就是在这个DateTime的基础上增加20天,返回新的DateTime对象*/ 8 //cookie.Expires = DateTime.Now.AddSeconds(10); 9 //如果不设定Expires超时时间,则关闭浏览器后Cookie失效 10 //如果设定Expires,则即使关闭浏览器,除非到期,否则再次打开浏览器,还能读取 11 cookie.Expires = DateTime.Now.AddMinutes(5);//AddDays(30) 12 context.Response.SetCookie(cookie);
不同浏览器Cookie是独立的。
Cookie是把信息储存在HTTP报文头中的。
Cookie无法跨域名读写。
1 context.Response.ContentType = "text/plain"; 2 HttpCookie lastCookie = context.Request.Cookies["c1"]; 3 context.Response.Write(lastCookie==null?"没有cookie":lastCookie.Value); 4 5 6 HttpCookie cookie = new HttpCookie("c1"); 7 cookie.Value = "rupeng.com"; 8 cookie.Domain = ".rupeng.com";//www.rupeng.com bbs.rupeng.com vip.rupeng.com 9 //Path的默认是“/”,当前域名下所有的页面都可以操作这个Cookie 10 cookie.Path = "/Day4/CookiePath1.ashx";//Path:谁能读我 11 context.Response.SetCookie(cookie);
设置Cookie的所有属性
除了name与value之外,Cookie还具有其他几个常用的属性。每个属性对应一个getter方法与一个setter方法。Cookie类的所有属性如表1.1所示。
表1.1 Cookie常用属性
属 性 名 |
描 述 |
String name |
该Cookie的名称。Cookie一旦创建,名称便不可更改 |
Object value |
该Cookie的值。如果值为Unicode字符,需要为字符编码。如果值为二进制数据,则需要使用BASE64编码 |
int maxAge |
该Cookie失效的时间,单位秒。如果为正数,则该Cookie在maxAge秒之后失效。如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。如果为0,表示删除该Cookie。默认为–1 |
boolean secure |
该Cookie是否仅被使用安全协议传输。安全协议。安全协议有HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false |
String path |
该Cookie的使用路径。如果设置为“/sessionWeb/”,则只有contextPath为“/sessionWeb”的程序可以访问该Cookie。如果设置为“/”,则本域名下contextPath都可以访问该Cookie。注意最后一个字符必须为“/” |
String domain |
可以访问该Cookie的域名。如果设置为“.google.com”,则所有以“google.com”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.” |
String comment |
该Cookie的用处说明。浏览器显示Cookie信息的时候显示该说明 |
int version |
该Cookie使用的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC 2109规范 |
Cookie的修改、删除
Cookie并不提供修改、删除操作。如果要修改某个Cookie,只需要新建一个同名的Cookie,添加到response中覆盖原来的Cookie。
如果要删除某个Cookie,只需要新建一个同名的Cookie,并将maxAge设置为0,并添加到response中覆盖原来的Cookie。注意是0而不是负数。负数代表其他的意义。
修改、删除Cookie时,新建的Cookie除value、maxAge之外的所有属性,例如name、path、domain等,都要与原Cookie完全一样。否则,浏览器将视为两个不同的Cookie不予覆盖,导致修改、删除失败。
Cookie的安全属性
HTTP协议不仅是无状态的,而且是不安全的。使用HTTP协议的数据不经过任何加密就直接在网络上传播,有被截获的可能。使用HTTP协议传输很机密的内容是一种隐患。如果不希望Cookie在HTTP等非安全协议中传输,可以设置Cookie的secure属性为true。浏览器只会在HTTPS和SSL等安全协议中传输此类Cookie。下面的代码设置secure属性为true:
1 Cookie cookie = new Cookie("time", "20080808"); // 新建Cookie 2 cookie.setSecure(true); // 设置安全属性 3 response.addCookie(cookie); // 输出到客户端
JavaScript操作Cookie
Cookie是保存在浏览器端的,因此浏览器具有操作Cookie的先决条件。浏览器可以使用脚本程序如JavaScript或者VBScript等操作Cookie。这里以JavaScript为例介绍常用的Cookie操作。例如下面的代码会输出本页面所有的Cookie。
1 <script>document.write(document.cookie);</script>
由于JavaScript能够任意地读写Cookie,有些好事者便想使用JavaScript程序去窥探用户在其他网站的Cookie。不过这是徒劳的,W3C组织早就意识到JavaScript对Cookie的读写所带来的安全隐患并加以防备了,W3C标准的浏览器会阻止JavaScript读写任何不属于自己网站的Cookie。换句话说,A网站的JavaScript程序读写B网站的Cookie不会有任何结果。
Session
Session又称为会话状态,是Web系统中最常用的状态,用于维护和当前浏览器实例相关的一些信息。我们控制用户去权限中经常用到Session来存储用户状态。
Session是一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。
如果说Cookie机制是通过检查客户身上的“通行证”来确定客户身份的话,那么Session机制就是通过检查服务器上的“客户明细表”来确认客户身份。Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了。
Session的生命周期
Session保存在服务器端。为了获得更高的存取速度,服务器一般把Session放在内存里。每个用户都会有一个独立的Session。如果Session内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。因此,Session里的信息应该尽量精简。
Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。用户每访问服务器一次,无论是否读写Session,服务器都认为该用户的Session“活跃(active)”了一次。
Session的有效期
由于会有越来越多的用户访问服务器,因此Session也会越来越多。为防止内存溢出,服务器会把长时间内没有活跃的Session从内存删除。这个时间就是Session的超时时间。如果超过了超时时间没访问过服务器,Session就自动失效了。
Session的常用方法
Session中包括各种方法,使用起来要比Cookie方便得多。Session的常用方法如表1.2所示。
表1.2 HttpSession的常用方法
方 法 名 |
描 述 |
void setAttribute(String attribute, Object value) |
设置Session属性。value参数可以为任何Java Object。通常为Java Bean。value信息不宜过大 |
String getAttribute(String attribute) |
返回Session属性 |
Enumeration getAttributeNames() |
返回Session中存在的属性名 |
void removeAttribute(String attribute) |
移除Session属性 |
String getId() |
返回Session的ID。该ID由服务器自动创建,不会重复 |
long getCreationTime() |
返回Session的创建日期。返回类型为long,常被转化为Date类型,例如:Date createTime = new Date(session.get CreationTime()) |
long getLastAccessedTime() |
返回Session的最后活跃时间。返回类型为long |
int getMaxInactiveInterval() |
返回Session的超时时间。单位为秒。超过该时间没有访问,服务器认为该Session失效 |
void setMaxInactiveInterval(int second) |
设置Session的超时时间。单位为秒 |
void putValue(String attribute, Object value) |
不推荐的方法。已经被setAttribute(String attribute, Object Value)替代 |
Object getValue(String attribute) |
不被推荐的方法。已经被getAttribute(String attr)替代 |
boolean isNew() |
返回该Session是否是新创建的 |
void invalidate() |
使该Session失效 |
Tomcat中Session的默认超时时间为20分钟。通过setMaxInactiveInterval(int seconds)修改超时时间。可以修改web.xml改变Session的默认超时时间。例如修改为60分钟:
<session-config>
<session-timeout>60</session-timeout> <!-- 单位:分钟 -->
</session-config>
注意:<session-timeout>参数的单位为分钟,而setMaxInactiveInterval(int s)单位为秒。
利用Session实现重定向:
1 public const string LOGINURL = "LoginUrl";//尝试登录的时候的页面地址 2 //=============================================================================================================// 3 if (username == null)//如果没登录,则重定向到登陆页面 4 { 5 context.Session[Login.LOGINURL] = context.Request.Url.ToString();//把当前地址存到Session中 6 context.Response.Redirect("Login.ashx"); 7 }
Session原理:
1 private const string RUPENGSESSIONID = "RupengSessionId"; 2 3 private HttpContext context; 4 private string sessionId; 5 public RupengSession(HttpContext context) 6 { 7 this.context = context; 8 HttpCookie cookie = context.Request.Cookies[RUPENGSESSIONID]; 9 if (cookie==null) 10 { 11 CreateSession(); 12 } 13 else 14 { 15 this.sessionId = cookie.Value; 16 } 17 } 18 19 private void CreateSession() 20 { 21 Guid guid = Guid.NewGuid(); 22 this.sessionId = guid.ToString(); 23 HttpCookie cookie = new HttpCookie(RUPENGSESSIONID); 24 cookie.Value = sessionId; 25 context.Response.SetCookie(cookie); 26 } 27 28 public void SetValue(string name, string value) 29 { 30 string fullpath = context.Server.MapPath("~/MySession/" + sessionId); 31 Dictionary<string, string> dict; 32 if (File.Exists(fullpath))//如果文件存在,则先把之前的数据反序列化出来 33 { 34 using (Stream stream = File.OpenRead(fullpath)) 35 { 36 BinaryFormatter bf = new BinaryFormatter(); 37 dict = (Dictionary<string, string>)bf.Deserialize(stream); 38 } 39 } 40 else 41 { 42 dict = new Dictionary<string, string>();//如果不存在,则创建空的字典 43 } 44 dict[name] = value; 45 //dict.Add(name, value);//设置值 46 using (Stream stream = File.OpenWrite(fullpath))//重新序列化把dict保存到文件 47 { 48 BinaryFormatter bf = new BinaryFormatter(); 49 bf.Serialize(stream,dict); 50 } 51 } 52 53 public string GetValue(string name) 54 { 55 string fullpath = context.Server.MapPath("~/MySession/" + sessionId); 56 Dictionary<string, string> dict; 57 if (File.Exists(fullpath))//如果文件存在,则先把之前的数据反序列化出来 58 { 59 using (Stream stream = File.OpenRead(fullpath)) 60 { 61 BinaryFormatter bf = new BinaryFormatter(); 62 dict = (Dictionary<string, string>)bf.Deserialize(stream); 63 } 64 } 65 else 66 { 67 dict = new Dictionary<string, string>();//如果不存在,则创建空的字典 68 } 69 if (dict.ContainsKey(name)) 70 { 71 return dict[name]; 72 } 73 else 74 { 75 return null; 76 } 77 } 78 79 /* 80 public void SetValue(string value) 81 { 82 string fullpath = context.Server.MapPath("~/MySession/" + sessionId); 83 File.WriteAllText(fullpath, value); 84 } 85 86 public string GetValue() 87 { 88 string fullpath = context.Server.MapPath("~/MySession/" + sessionId); 89 if (File.Exists(fullpath) == false) 90 { 91 return null; 92 } 93 return File.ReadAllText(fullpath); 94 }*/ 95 }
进程外Session
Session默认是保存在Web服务器内存中的(InProc),当Web服务器重启之后Session就丢失了,造成用户反复登录的问题。
Session保存在SQLServer中:
1、Session保存在SQLServer中配置方法
1)运行.NetFramework安装目录下对应版本的aspnet_regsql.exe 来创建相关的数据库、表和存储过程等,比如:
C:\Windows\Microsoft.NET\Framework\v4.0.30319>aspnet_regsql.exe -ssadd -sstype p -S 127.0.0.1 -U sa -P 123456
其中-sstype p表示数据库名固定为ASPState,-S(大写)为数据库服务器地址,-U和-P分别为数据库的用户名和密码,参数详细解释见 http://blog.csdn.net/yuanzhuohang/article/details/6758304
2)修改web.config中sessionState节点的配置:<sessionState mode="SQLServer" timeout="20" sqlConnectionString="server=.;uid=sa;password=123456;" ></sessionState>