教程集 www.jiaochengji.com
教程集 >  脚本编程  >  Asp.net  >  正文 asp.net Session会话层使用与管理方法

asp.net Session会话层使用与管理方法

发布时间:2016-12-03   编辑:jiaochengji.com
教程集为您提供asp.net Session会话层使用与管理方法等资源,欢迎您收藏本站,我们将为您提供最新的asp.net Session会话层使用与管理方法资源

1. 保留默认的会话模块,但编写自定义的状态提供程序来更改存储介质。这样,我们还有机会重写一些用于在存储与session之间运载会话数据的辅助类。

  2. 保留默认的会话模块,但替换会话id生成器。
  3. 将默认的会话状态模块替换成自己的。这种方法提供了最好的灵活性,但也最为复杂,建议仅当的确必要且知道确切的实现方法才使用这种方案。
构建自定的会话状态提供程序
  会话状态提供程序是一种组件,负责为当前会话数据进行服务。当请求需要状态信息时,该组件便会被调用,从给定的存储介质中获取数据,并返回给主调模块。在请求结束时,也会被调用,以便将提供的数据写入存储层。
  request.cookies集合读取。
无cookie会话
  为使会话状态正常工作,客户端必须能够将会话id上传至服务器端应用程序。这个过程具体细节取决于应用程序的配置。asp.net应用程序通过配置文件的<sessionstate>定义会话特有的设置。会确定cookie的支持方式,我们需要将cookieless属性设置为下表中的某个值,这些值为httpcookiemode枚举类型:
  在禁用cookie支持的情况下,假设用户通过这样的url来请求某个页面:
  http://www.contoso.com/test/sessions.aspx
  浏览器地址栏中显示的地址会发生一些变化的(其中包含会话id),如下所示:
  http://www.contoso.com/test/(s(sylgasdfueoruikfjoiueriljk))/sessions.aspx
  当会话状态模块实例化时,它会检查cookiesless属性值,如果发现cookie被禁用,请求会被重定向到一个被修改的虚拟url(http状态码为302),其中包含一个会话id,刚好在页面名的前面。当再次开始处理请求时,这个会话id会嵌入请求中。这个请求会由一个特殊的isapi筛选器(aspnet_filter.exe组件)做预处理--解析其url,若带有会话id,则将其重写为正确的url。被检测到的id会存储在单独的http标头(aspfiltersessionid)中,以便稍后使用。
无cookie会话带来的问题
  当会话开始时,不论用户发出的是否为应用程序页面的绝对url,无cookie都会引发重定向。
  若使用cookie,且在地址栏填入另一个应用程序的地址,那么在返回之前的页面时,获取的是相同的会话值。如果禁用cookie,当页面回发时会自动通过相对url来实现,不受影响。但如果使用绝对url链接,则会造成会话数据则会丢失,这种情况下,总会创建新的会话。例如下面的代码就会打断当前会话:
<pre>
<a runat="server href="/test/sessions.aspx">click</a>
</pre>
  有什么办法能够自动修改链接和超链接中的绝对url,使其融入会话id信息?
  我们可以使用httpresponse类的applyapppathmodifier方法:
<pre>
<a href='<% =response.applyapppathmodifier("test/page.aspx")%>' >click</a>
</pre>
  applyapppathmodifier方法接受一个代表相对url的字符串,返回的是带有会话信息的绝对url。这个技巧非常适合将http页面重定向到https页面,这时必须使用完整的绝对地址。注意,如果会话cookie是启用的,或传入的路径是绝对路,那么applyapppathmodifier返回的则是原始的url。
  我们不能在服务器端表达式(即,带有runat=server属性的表达式)中使用<%...%>代码块。该代码块之所以能在上述代码工作是因为<a>标签是纯文本,没有runat属性。注意,这里所说的代码块与数据绑定表达式<%#...%>没有任何关系。之所以不能在服务器端表达式中使用<%...%>代码块,是因为runat属性会指示将当前标签强制创建为服务器对象,而服务器对象不会处理这种代码块。
无cookie会话与安全
  使用无cookie会话引发的另一个问题与安全有关。会话劫持(session hijacking)是最常见的攻击类型之一,它通过生成另一个合法用户的会话id来访问外部系统。为理解这种攻击方式,可以这样做:将应用程序配置为不使用cookie,并访问某个页面,获取带有会话id的url(可取自浏览器的地址栏),并立即通过电子邮件发送给一个您的朋友。让对方将该url粘贴到自己浏览器的地址栏中,并单击“转到”。只要您的会话还是活动的,那么您的朋友也能访问相同的会话。
  出于对系统安全的考虑,生成随机id很关键,因为这会使攻击者很难猜测到有效的会话id。对于无cookie会话,会话id暴露在地址栏中,对外界可见。因此,如果要将私人或敏感信息存储在会话中,建议使用安全嵌套字层(secure sockets layer,ssl)或传输层安全性(transport layer security,tls)对浏览器和服务器间包含会话id的通信进行加密。
  此外,若用户认为这样会降低安全性,我们还应为其提供注销功能,并调用abandon方法。这样会缩短在某个攻击者设法找到合法用户的会话id的时间。而且从安全性角度来讲,在使用无cookie会话时,有必要对应用程序进行配置,使其避免重复使用过期的会话id。在asp.net中,该行为可通过<sessionstate>区段进行配置。
会话状态的配置
  在asp.net 1.x向asp.net 2.0过渡的过程中,<sessionstate>区段的选项也随之增加,如下所示:
<pre>
<sessionstate
mode="off|inproc|stateserver|sqlserver|custom"
timeout="number of minutes"
cookiename="session cookie name"
cookieless="http cookie mode"
regenerateexpiredsessionid="true|false"
sqlconnectionstring="sql connection string"
sqlcommandtimeout="number of seconds"
allowcustomsqldatabase="true|false"
usehostingidentity="true|false"
partitionresolvertype=""
sessionidmanagertype="custom session id generator"
stateconnectionstring="tcpip=server:port"
statenewworktimeout="number of seconds"
customprovider="custom provider name">
<providers>
...
</providers>
</sessionstate>
</pre>
  sessionstate的属性说明见下表:
  此外,子区段<providers>用户设置所有自定义会话状态存储提供程序。
会话的生存期
  会话状态的生存期起始于首个数据项被添加到内存中的字典时。该字典是一个sessiondictionary的内部类实例。
session_start事件
  会话启动事件与会话状态无关。session_start事件将在会话状态模块为用户的首个请求提供服务且需要新会话id时引发。asp.net运行库能在单个会话上下文中为多个请求服务,但只有第一个请求会引发session_start事件。
  若不向字典中写入数据,便会在请求页面时创建新的会话id并引发session_start事件。
session_end事件
  session_end事件用于通知会话的结束,并执行终止会话涉及的清理代码。但应注意,该属性要求当前处于inproc模式下(会话数据存储在asp.net工作线程)。
  为使session_end引发,会话状态必须事先已经存在。这意味着,我们必须在会话状态中存储一些数据,且至少完成一个请求。当第一个值被添加到会话字典中时,会有一个对应项被插入asp.net缓存。该行为针对的是进程内状态提供程序,进程外状态服务器和sql server状态服务都不涉及cache对象。
  添加到缓存的会话状态项会被指定一个可调的过期时间(会话超时设置中的间隔时间),只要有请求在当前会话上下文中处理,可调的时间会自动更新。会话状态模块会在处理endrequest事件时重置这个超时设置。该模块只要对缓存执行一次读取操作,就能达到期望的效果。asp.net cache对象的内部结构,使其能够估算出该可调时间段的长短。因此,当缓存项过期时,会话状态也已超时。
  过期项会自动从缓存中移除。作为过期策略的一部分,会话状态模块还会指定一个移除回调函数。缓存对象会自动调用该移除函数,而该函数会引发session_end事件。
  cache中代表会话状态的项无法在system.web程序集之外访问,更不能进行枚举,因为它们被置于缓存的系统保留区域内。也就是说,我们不能以编程的方式访问位于另一个会话中的数据,移除就更谈不上了。
为什么会话状态有时会丢失
  session对象中的值可以编程方式移除,也会在会话超时或被放弃时由系统移除。但在某些情况下,会话状态会莫名其妙的丢失,这是为什么呢?
  当处在inproc模式下时,会话状态会被映射到处理当前请求的appdomain内存空间中。因而,会话状态会受进程回收和appdomain重启的影响。asp.net工作线程会周期性的重启以便保持总体上的良好性能,重启后,会话状态便会丢失。进程回收的执行会根据内存的占用率和被服务的请求数。虽然该过程是周期性的,但无法估计出回收的间隔。因此,在设计基于会话的、进程内的应用程序时,应充分考虑这个问题。会话状态可能在试图访问时不存在。使用异常处理,还是使用恢复技术,要根据具体的应用程序来分析。
  当某页面运行出现错误时,会话状态会受到怎样的影响?当前的会话字典是会被保存还是丢失?若页面在请求结束时发生错误(server对象的getlasterror方法返回一个异常对象),会话状态则不会被保存。然而,如果在异常处理程序中通过调用server.clearerror方法来重置异常状态,那么会话状态数据便会按常规方式保存,就像没有发生错误一样。
将会话状态保存在远程服务器中
  对于前面提到的inproc模式下会话状态会丢失的问题,可以利用进程外状态提供程序来解决。但如果这样的话,会话状态不存储在asp.net工作线程中,需要一层额外的代码来对存储介质中的数据进行序列化和反序列化,该操作发生在请求被处理期间。
  将会话数据从外部存储区复制到本地会话字典中,可能造成状态管理进程的性能下降15%--25%。
  若选择进程外状态提供程序,应考虑在应用程序进入生产环境前事先建立运行时环境。这涉及启用有关stateserver的windows服务或配置sqlserver日期和时间的总刻度数的形式写入,作为int64类型读取。
  对于复杂对象,只要它被标记为“可序列化”,则会通过binaryformatter类对其进行序列化,其速度相对较慢。简单类型和复杂类型都会使用同一个流,但所有非基本类型由同一个类型id来标识。
  我们不应该将任何对象都存储在session中。如果使用进程外方案,对dataset的存储应该谨慎。这与dataset类的序列化过程有关。由于dataset是复杂类型,它是通过二进制格式化程序进行序列化的。而dataset本身的序列化会生成许多xml数据,而这会对应用程序造成严重的缺陷,尤其对于存储大量数据的大型应用程序。
会话数据的存储
  若工作在stateserver模式下,整个httpsessionstate对象的内容会被序列化到一个外部应用程序,即一个名为aspnet_state.exe的microsoft windows nt服务。该服务用于在请求结束时对会话状态进行序列化。在内部,该服务使用字节数组来存储每个会话状态。若开始处理新的请求,与给定会话id对应的数组会被复制到内存流中,然后被反序列化成内部的会话状态项对象。该对象代表整个会话的内容。页面实际使用的httpsessionstae对象只是其应用程序编程接口。
stateserver提供程序的配置
  若采用进程外存储方案,会话状态的生存期便会被延迟。这样一来,应用程序的健壮性更强。通过将会话状态与页面分离,我们还能够将现有的应用程序逐步向web farm和web garden架构转化。
  asp.net会话状态提供程序是一个叫aspnet_state.exe的windows服务,该服务的可执行文件位于asp.net的安装文件夹:%windows%microsoft.netframework[version]。
  注意,具体的路径取决于实际运行的.net framework的版本。在使用状态服务前,应确保该服务在本地或用于存储会话的远程计算机上正常运行。
  我们需要为asp.net应用程序指定运行会话状态服务的计算机的ip地址。为启用远程会话状态,我们需要在web.config中进行配置:
<pre>
<configuration>
<system.web>
<sessionstate mode="stateserver"
stateconnectionstring="tcpip=mymachine:42424" />
</system.web>
</configuration>
</pre>
  服务器名既可以是ip地址,也可以是计算机名称。
  状态服务器不会为请求者设置任何身份验证障碍,这样,网络用户可以自由访问会话数据。为保护会话状态,应确保其只能接受来自web服务器计算机的访问。为此,我们可以使用防火墙、ipsec策略或安全网络10.x.x.x,这样,外部攻击都便不能直接访问了。我们还可以修改其服务端口,修改注册表中的键值“hkey_local_machinesystemcurrentcontrolsetservicesaspnet_stateparameters”即可修改状态服务的端口。
  asp.net应用程序会在加载后立即尝试连接到会话状态服务器。状态服务会使用.net remoting进行数据通信。
  默认情况下,状态服务器只监听本地连接,如果状态服务器和web服务器是不同的计算机,我们需要启用远程连接。为此,我们只要在注册表中修改键值“hkey_local_machinesystemcurrentcontrolsetservicesaspnet_stateallowremoteconnection”,将其设置一个非0值即可。
将数据保存到sql server
  如果应用程序对健壮性要求较高,比如状态提供服务被停用后,数据仍然不会丢失,不妨将sql server服务。
  若asp.net工作在sql server模式下,会话数据存储在一个专用的数据库表中,因此,即使sql server崩溃,会话数据也不会丢失,但这需要更高的系统开销。
  为将sql server作为状态提供程序,需要对web.config文件进行配置:
<pre>
<configuration>
<system.web>
<sessionstate mode="sqlserver"
sqlconnectionstring="server=127.0.0.1;integrated security=sspi;" />
</system.web>
</configureation>
</pre>
  如果不通过allowcustomsqldatabase启用自定义数据库,那么该连接字符串中不能包含database和initial catalog这样的设置。仅当allowcustomsqldatabase设置被启用时,我们才可通过database和initial catalog指定数据库名称。
  连接字符串也可以引用定义在<connectionstring>区段中的连接字符串,连接字符串名称可以在<sessionstate>相应属性中指定。
  对数据库的访问凭据,我们可以通过用户id和密码来提供,也可以利用“集成安全性”。不论使用哪个帐户来访问sql server中的会话状态,都应确保用户至少拥有db_datareader和db_datawriter权限。还应注意,为配置存储会话状态的sql server环境,需要管理员权限,因为要创建新的数据库和存储过程。
  对于sql server模式下的会话状态,我们能指定自定义命令的超时值(以秒为单位)sqlcommandtimeout属性来进行设置。
sql server数据库的创建
  asp.net提供了两对用于配置数据库环境的脚本,以便创建必要的表、存储过程、触发器、作业等。
  第一对脚本为installsqlstate.sql和uninstallsqlstate.sql。它们能够创建一个aspstate数据和几个存储过程,但数据存储在tempdb数据库的几个表中。这样,如果sql server所处的计算机被重启,会话数据将丢失。
  另一对脚本为installperisistsqlstate.sql和uninstallperisistsqlstate.sql。与第一对脚本的不同之处是,它们创建的表在aspstate数据库中,是持久性的。共有两个表,表名分别为aspstatetempapplications和aspstatetempsessions。
  所有脚本可以在以下路径中找到:
  %systemroot%microsoft.netframework[version]
  包含这些脚本文件只是为了向后兼容,我们应使用aspnet_regsql.exe来安装和卸载sql会话状态。
  当前运行的每个asp.net应用程序对应于aspstatetempapplications表中的一条记录。下表对表中各列做了说明:
  aspstatetempsessions表用于存储实际的会话数据,每个活动的会话对应于表中的一条记录,下表描述了该表的结构:
  在安装会话的sql server支持时,还有一个作业被添加,它用于从会话状态数据库中删除过期的会话。该作业名称为aspstate_job_deleteexpiredsessions,默认配置是每分钟运行一次。
</pre>

您可能感兴趣的文章:
asp.net session必须了解的七点常识
asp.net Session会话层使用与管理方法
Go 语言 Session机制和 Cookie机制
ASP.NET创建Web服务管理Web服务状态
Go基础学习记录之如何在Golang中使用Session
asp.net Session丢失的解决方法
asp.net session实现用户登录的疑问
asp与asp.net的session共享
ASP.NET的Session使用浅析
有关php中session的疑惑

上一篇:asp.net checkboxlist 取值实例 下一篇:c# .net中下载文件及图片文件的防盗链功能实现方法
[关闭]
最近更新
浏览排行
~ ~