在做一些应用网站时,我们可能会碰到这样一种情况:整个项目是由多个网站组成的,而我们要实现用户从一个站点登录后,跳转到其他网站不需要重复登录,即实现单点登录。目前实现单点登录的技术也有好几种,这篇文章描述一下如何使用ASP.NET2.0和SQL Server来实现单点登录。一般在用户登录成功后,我们需要把用户登录成功的信息保存在Session里,但是Session的值只能保存在用户当前访问的站点下,只要我们实现了Session的跨站共享,也就基本上实现了用户在一个站点登录成功后在其他站点不需要重复登录,在这里,我们使用SQL Server来保存Session状态,实现多个站点共享Session。

  开发环境:WindowsXP、VS2005、.NET Framework 2.0、SQL Server 2000

  首先我们需要创建一个单独的数据库来保存Session状态,安装了Framework2.0后,我们可以在“C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727”目录下找到一个“InstallPersistSqlState.sql”的SQL文件,这个文件就是用来创建保存Session状态的数据库,只需要在查询分析器中执行一下就可以了,当然也可以使用“UninstallPersistSqlState.sql”这个文件来卸载已创建的状态数据库。

  “InstallPersistSqlState.sql”执行完毕后,刷新一下对象浏览器,我们就可以看到一个叫做“ASPState”的数据库,数据库中有两个表,“ASPStateTempApplications”是用来存储所有使用SQLServer保存状态的站点的,“ASPStateTempSessions”当然就是用来保存所有Session的了。如下图:


sql server 登录本机 server name sql server登录方式_数据库

  创建完数据库后,我们可以新建一个测试网站,来看一下Session状态是否可以保存到数据库中,当然测试之前我们还需要对web.config文件做一些设置。打开web.config,在<system.web>标签下创建<sessionState>标签,mode属性是说明把Session状态保存在什么地方,有状态服务器、内存、数据库等,这里我们要选择SQLServer。设置如下所示:


1. <system.web>  
2. <sessionState mode="SQLServer" sqlConnectionString="Data Source=127.0.0.1;User ID=sa;Password=;" timeout="60"/>  
3. </system.web>


  在测试Session状态时,有一点需要注意,就是如果我们在程序中没有给Session任何值,Session状态是不向数据库中保存的。我们随便给Session一个键值,运行后,使用查询分析器来看一下“ASPState”数据库中两个表的内容,如下:

ASPStateTempApplications表


sql server 登录本机 server name sql server登录方式_数据库_02

ASPStateTempSessions表


sql server 登录本机 server name sql server登录方式_SQL_03

下图为测试页上显示的Session内容:


sql server 登录本机 server name sql server登录方式_sql_04

  在这里我们需要解释一下AppID和SessionID,先看一下下面两张图中的SessionID,表ASPStateTempSessions中的SessionID比页面上多出了8位,就是后面的“64021378”,这段字符串其实是表ASPStateTempApplications里的AppID的十六进制表示,可以看出数据库中SessionID的值,是“页面SessionID+AppID”组合而成的。

  既然我们要实现的是跨站共享Session,那么我们需要创建另外一个测试站点2,也按照上述方法把Session状态保存到数据库中,下图显示了在浏览器中访问这两个站点后,“ASPStateTempSessions”表保存的Session信息:


sql server 登录本机 server name sql server登录方式_数据库_05

  这两条SessionID前面的部分相同,不同的地方是后面8位标识AppID的值不同,在ASPState库中,判断是否为同一用户是根据SessionID为条件的,虽然这里用户是同一人,但访问的站点不同,SessionID也就不相同了。下面我们要做的就是忽略SessionID里面的站点标识,这样就ASPState就可以把来自同一用户的多个站点访问当做是同一站点访问,Session值也就可以在多个站点共享了。

  在ASPState库里,我们需要修改“TempGetAppID”这个存储过程,把里面两句“WHERE AppName = @appName”注释掉就可以了。在这里,应注意修改完存储过程后,需要把ASP.NET网站程序重新启动一下。

1. ALTER  PROCEDURE dbo.TempGetAppID  
2. @appName    tAppName,  
3. @appId      int OUTPUT  
4. AS  
5. SET @appName = LOWER(@appName)  
6. SET @appId = NULL  
7.   
8. SELECT @appId = AppId  
9. FROM [ASPState].dbo.ASPStateTempApplications  
10. --WHERE AppName = @appName  
11.   
12. IF @appId IS NULL BEGIN  
13.     BEGIN TRAN          
14.   
15.     SELECT @appId = AppId  
16.     FROM [ASPState].dbo.ASPStateTempApplications WITH (TABLOCKX)  
17.     --WHERE AppName = @appName  
18.       
19.     IF @appId IS NULL  
20.     BEGIN  
21.         EXEC GetHashCode @appName, @appId OUTPUT  
22.           
23.         INSERT [ASPState].dbo.ASPStateTempApplications  
24.         VALUES  
25.         (@appId, @appName)  
26.           
27.         IF @@ERROR = 2627   
28.         BEGIN  
29.             DECLARE @dupApp tAppName  
30.           
31.             SELECT @dupApp = RTRIM(AppName)  
32.             FROM [ASPState].dbo.ASPStateTempApplications   
33.             WHERE AppId = @appId  
34.               
35. 'SQL session state fatal error: hash-code collision between applications ''%s'' and ''%s''. Please rename the 1st application to resolve the problem.',   
36.                         18, 1, @appName, @dupApp)  
37.         END  
38.     END  
39.   
40.     COMMIT  
41. END  
42.   
43. RETURN 0

  好了,现在我们可以测试一下了,在一个站点中给Session赋个值,然后在另一个站点中取一下,是不是可以取出来呢,如果可以,那么恭喜你,你已经实现了Session共享,应用到你的系统中吧。