共计 4713 个字符,预计需要花费 12 分钟才能阅读完成。
每个客户端在访问网站时,都会创建相应的 Session,用来保存客户的状态信息,网站如果做了负载均衡,session 共享是要做的,IIS 对于 session 的存储有五种模式
一、ASP.Net session 存储方式
1、InProc 模式 (进程内模式)。为默认设置。
会话状态存储在 Web 服务器上的内存中。
2、StateServer 模式 (状态服务器模式)。
会话状态存储在一个名为 ASP.Net 状态服务的单独进程中。这确保了在重新启动 Web 应用程序时会保留会话状态,并让会话状态可用于网路场中的多个 Web 服务器。
3、SQL Server 模式。
会话状态存储到一个 SQL Server 数据库中。这确保了在重新启动 Web 应用程序时会保留会话状态,并让会话状态可用于网路场中的多个 Web 服务器。
4、Custom 模式
此模式允许您指定自定义存储提供程序。
5、Off 模式
此模式禁止会话状态。
二、使用 StateServer 存储 session
如果网站做了负载均衡,对于 session 存储就只能选择 2、3、4 了,下面先来介绍一下 StateServer 模式,首先得开启状态服务
然后再对 web 站点的“会话状态”进行设置
启用本机的状态服务
会自动在 web.config 里生成配置文件(如果不能生成就手动添加)
<sessionState mode=”StateServer”stateConnectionString=”tcpip=loopback:42424″ timeout=”20″ />
但是这里就存在一个问题,如果每台服务器都照上面配置,各服务器的 Session 都存储在本机的 StateServer 里面,还是没有启动共享的作用,这里就需要让一台 StateServer 共享出来让其他服务器访问,并将 Session 存储到上面,运行 regedit → 打开注册表 → 找到 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\aspnet_state\Parameters 节点 → 将 AllowRemoteConnection 的键值设置成“1”(1 为允许远程电脑的连接,0 代表禁止)
也可以修改 StateServer 的端口
接下来将其它服务器中 web.config 的配置文件进行修改(sessionState 指向开启了允许远程访问的 StateServer)
<sessionState mode=”StateServer”stateConnectionString=”tcpip=10.16.5.30:22222″ timeout=”20″ />
用 StateServer 这种共享式的 session 存储方式不仅有安全隐患,而且像上面那台共享的 StateServer 只要重启服务器,所有的 session 都会丢失,所以这种 session 存储方式不是很完美,用 StateServer 存储 sesssion 比较适合单机 IIS 开启多进程的。
三、使用 SQL server 存储 session
要做保证安全并且不会因为重启服务器导致 session 丢失,那就要用 sql server 来存储 session,ASP.NET 2.0 版本后微软提供了 aspnet_regsql.exe 工具可以方便的配置 Session 数据库. 该工具位于 Web 服务器上的系统根目录 Microsoft.NETFramework 版本号文件夹中
cd C:\Windows\Microsoft.NET\Framework64\v4.0.30319
aspnet_regsql.exe -ssadd -sstype c -d <Database Name> -S <SQL Server IP> -U <User Name> -P <Password>
aspnet_regsql.exe -ssadd -sstype c -d ASPState -S 10.16.5.36 -U sa -P HAha789
注:<Database Name> 为数据库名为 ASPState,<SQL Server IP> 为数据库实例名像 IBM-PC\SQLEXPRESS(若数据库不是 2005 的不要写 ip 地址,否则会连接失败),<User Name> 为 sa(或与 sa 同等权限的),<Password> 为 sa 用户名的密码会话定义成功,但是会提示在 web 应用中进行相应的配置,此时查看 SQLServer 会发现增加了数据库 ASPState,但是没有表。
在命令行下运行如下命令:aspnet_regsql.exe -ssadd -sstype p -S <SQL Server IP> -U <User Name> -P <Password>
aspnet_regsql.exe -ssadd -sstype p -S 10.16.5.36 -U sa -P HAha789
该命令对此应用进行了持久化操作。这时会看到 ASPState 数据库里面多了两张表,ASPStateTempSession 就可以用来保存 Session,接下来要对 web 站点的“会话状态”进行设置
ASPStateTempSessions 表中的 SessionID , 包括两个部分:网站生成的 24 位 SessionID 及 8 位 AppId 组成,对于不同的站点,其 AppId 和 AppName 也不同,在能够在不同站点下 Session 共享,就得保证这个 32 位的 SessionID 一致,所以可以通过修改存储过程 TempGetAppID,使其得到的 SessionID 与 AppName 无关,修改 TempGetAppID 如下
修改 web.config(在数据库中为 ASPState 单独分配一个帐户)
<sessionState mode="SQLServer" sqlConnectionString="data source=10.16.5.36;user id=sa;password=HAha789" cookieless="false" timeout="20"></sessionState>
这样就实现了 sql server 对 session 的存储,当然也可以用 memcache 来存储 session
四、ASP.NET 错误,验证视图状态 MAC 失败
但在在网站登录访问时却报错了“ASP.NET 错误,验证视图状态 MAC 失败”,baidu 了一下,大部分人都说是在页里或 web.config 里加 EnableEventValidation=”false” EnableViewStateMac=”false” ViewStateEncryptionMode=”Never” 这些属性的设置。但是这并不从根本上解决问题,相反这样做了反而更加不安全。不能说出错就不用了?出错得解决问题,得从根本上解决问题。
分析错误原因:
ASP.NET 中有很多涉及到加密的东西,比如 ViewState,比如 FormsAuthenticationTicket,这些东西都是要传送到客户端的,加密才能保障其安全性。加密就得有个私钥,但这个私钥我们并没有指定啊,那是因为 ASP.NET 自动生成的。但是如果是在网络场或群集中,或者在某些做了 CDN 加载的虚拟主机中,由于涉及到多台服务器 ASP.NET 就无法为各台机器自动生成相同的私钥,这就造成了这个服务器产生的数据,那台服务器解析不出来。于是就出错了。怎么办?既然 ASP.NET 在多台服务器上无法自动随机生成相同的私钥,那只有我们自己指定了。
MachineKey 生成工具,自动生成代码
https://www.fishlee.net/tools/machinekeygenerator
将生成的 Machinekey 插入到 web.config 中:
<system.web>
<machineKey validationKey="A89B01ED6C356FCFEEB884EA523D7827F719C7A9F26BCC808A109C516D57DF91D2D7612127F06957C6643913DB893F66492A2FB85D44805735BA96DF41071B0F" decryptionKey="E9F179A7EF94763ABD9A79B07BA61F49550235125FADEF942BD2045B2A9803C8" validation="SHA1" decryption="AES" />
</system.web>
MachineKey 的作用:
ASP.net 使用 forms authentication 时的 cookie 数据的加密和解密。以确保这部分数据不会被篡改 viewstate 数据的加密和解密。以确保这部分数据不会被篡改。使用进程外 session(out-of-process session)时,对会话状态标识进行验证。利用 SessionStateMode 的 SQLServer 来实现 session 共享,毕竟是微软的东西,具有一定的局限行,只能是 sql server。其实 session 共享可以用其他的数据库,比如 memcache、redis
五、ASP.NET 状态数据库 FAQ
1、如果把 SESSION 值存放到数据库中去,用户关闭了程序那怎么样清空数据库里的 SESSION 值呢?
实际 ASP.NET 在创建状态数据库的时候会在 SQL Server 代理(SQL Server Agent)的作业中添加一个作业,名称为 < 状态数据库名 >_Job_DeleteExpiredSessions。如果打开 SQL Server 代理服务数据库可以通过添加的状态记录的超时时间字段(Exprires)定期对超时的状态数据进行删除。
2、ASPStateTempSessions 表中的 SessionId 字段如何使用?
数据库中此表的 SessionID 字段的值,由 SessionID 和 AppID 共同组成,最后 8 位为 AppID 所以,后 8 位之前一定是 SessionID。例如,存储在数据库中的值为 ”ekr30c3mwvnc3145yrswew3a037e5e5a”,后 8 位的 ”037e5e5a” 为 AppID,而前面的 ”ekr30c3mwvnc3145yrswew3a” 为应用程序中你可以使用 Session.SessionID 获得的字符串。
3、如何判断 Session 何时被更新的?
Session 记录被更新时会同时更新 Expires 和 LockDateLocal,Expires 字段为 UTC 时间,如果想通过本地之间进行比较判断还是需要使用 LockDateLocal。
4、获得 Web.config 配置文件节点信息的程序?
” 获得 Web.config 文件配置实例
Dim configuration As System.Configuration.Configuration = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(“~/web.config”)
” 获得状态配置节点实例
Dim mSessionStateSection As System.Web.Configuration.SessionStateSection = CType(configuration.GetSection(“system.web/sessionState”),System.Web.Configuration.SessionStateSection)
” 获得状态模式
Response.Write(mSessionStateSection.Mode)
” 获得状态超时时间
Response.Write(mSessionStateSection.Timeout)