使用asp.net和状态服务器在两个网站之间共享会话

ppo*_*zos 13 c# asp.net iis state

我在IIS 7.5下有两个完全相同的网站托管在两台不同的机器上.ASP.NET状态服务正在我的机器上运行,web.config在两个站点中都使用以下代码更新:

<sessionState mode="StateServer" stateConnectionString="tcpip=192.168.1.77:42424" cookieless="false" timeout="120"/>
Run Code Online (Sandbox Code Playgroud)

允许远程连接在注册表中设置为1,以便第二个网站访问状态服务器.

两个网站都具有相同的机器密钥:

<machineKey validationKey="7CB8DF6872FB6B35DECD3A8F55582350FEE1FAB9BE6B930216056C1B5BA69A4C5777B3125A42C4AECB4419D43EC12F168FD1BB887469798093C3CAA2427B2B89" decryptionKey="02FC52E4C71544868EE297826A613C53537DF8FDAF93FA2C64E9A5EF0BA467FB" validation="SHA1" decryption="AES" />
Run Code Online (Sandbox Code Playgroud)

此外,两个站点在IIS中配置为具有相同的标识符.

我想要做的是这两个站点共享相同的会话数据,例如能够执行以下操作:

// At web site 1: 
Session["key"] = "value"
Run Code Online (Sandbox Code Playgroud)

// At web site 2:
// Read session value from the other web site
string result = Session["key"]
Run Code Online (Sandbox Code Playgroud)

问题是我无法完成这个测试,真的无法理解我做错了什么.

任何可能有帮助的想法?

Hoà*_*ong 13

我知道这个问题在5年前得到了回答,但今天我想我可以在其中提供更多信息.

首先,这不是在两个IIS应用程序之间共享会话数据的官方方式,也不是最流行的方式."看似官方"的方式是使用SQL Server会话.

如果您因任何原因无法使用SQL服务器,那么我们可以稍微调整一下IIS应用程序,以便我们可以使用进程外会话,即StateServer会话状态模式.

为了使它有效,有很多事情要做:

  1. 2应用程序的会话cookie必须设置为相同的域名.例如
<httpCookies domain=".your.site"/>
Run Code Online (Sandbox Code Playgroud)
  1. 必须匹配机器密钥.您可以执行标准的Web.config字段加密,以使其更安全,但这是可选的.
<machineKey validationKey="[your_key]" 
    decryptionKey="[your_decryption_key]" validation="SHA1" />
Run Code Online (Sandbox Code Playgroud)
  1. 会话状态模式设置为状态服务器

将(1),(2),(3)放在一起:

<system.web>
    <httpCookies domain=".your.site"/>
    <machineKey validationKey="your_key" decryptionKey="your_decryption_key" validation="SHA1" />
    <sessionState mode="StateServer" timeout="60" />
    ...
Run Code Online (Sandbox Code Playgroud)
  1. 应用程序名称必须匹配.如果不是,则只能共享会话ID,而不能共享会话数据.问题是您无法在Web.config中配置应用程序名称.然而,我们可以创建自己的配置,然后通过反射注入它.只需将以下代码放在Global.asax.cs中:

    public override void Init()
    {
        base.Init();
        try
        {
            // Get the app name from config file...
            string appName = ConfigurationManager.AppSettings["ApplicationName"];
            if (!string.IsNullOrEmpty(appName))
            {
                foreach (string moduleName in this.Modules)
                {
                    IHttpModule module = this.Modules[moduleName];
                    SessionStateModule ssm = module as SessionStateModule;
                    if (ssm != null)
                    {
                        FieldInfo storeInfo = typeof(SessionStateModule).GetField("_store", BindingFlags.Instance | BindingFlags.NonPublic);
                        SessionStateStoreProviderBase store = (SessionStateStoreProviderBase)storeInfo.GetValue(ssm);
                        if (store == null) //In IIS7 Integrated mode, module.Init() is called later
                        {
                            FieldInfo runtimeInfo = typeof(HttpRuntime).GetField("_theRuntime", BindingFlags.Static | BindingFlags.NonPublic);
                            HttpRuntime theRuntime = (HttpRuntime)runtimeInfo.GetValue(null);
                            FieldInfo appNameInfo = typeof(HttpRuntime).GetField("_appDomainAppId", BindingFlags.Instance | BindingFlags.NonPublic);
                            appNameInfo.SetValue(theRuntime, appName);
                        }
                        else
                        {
                            Type storeType = store.GetType();
                            if (storeType.Name.Equals("OutOfProcSessionStateStore"))
                            {
                                FieldInfo uribaseInfo = storeType.GetField("s_uribase", BindingFlags.Static | BindingFlags.NonPublic);
                                uribaseInfo.SetValue(storeType, appName);
                            }
                        }
                    }
                }
            }
    
        }
        catch (Exception ex)
        {
            log.Error(ex.Message, ex);
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    积分转到pfemiani,李晨,以及我不记得是谁在一个代码项目的评论中把它放在一起.请注意,pfemiani的答案对我不起作用,但将它与李晨的帖子结合起来了.

  2. 确保ASP .NET状态服务正在运行.这是现在保存会话数据的地方.

  • 这对我有用.特别是第4点是其他SO答案中缺少的. (3认同)

mwa*_*ker 4

您需要一种方法来说服您的浏览器发送相同的 ASP.NET 会话 cookie,无论它访问哪个站点。

如果请求中不存在 cookie,则将使用该密钥创建一个新会话。

我认为您可以通过一些偷偷摸摸的 DNS 配置让浏览器保留密钥 - 如果您将http://website1.mydomain.com/http://website2.domain.com/指定为您网站的地址,那么将 ASP.NET 会话 cookie 的域设置为“domain.com”,然后您的浏览器会将其发送到两个站点,并且会话应该被共享。

您还可以在 ASP.NET 中使用 cookieless 模式,并从生成的 URL 中获取会话 ID。

  • 关于无 cookie 模式的警告:它非常不安全。会话 ID 位于 URL 中,因此人们可以简单地获取它并以您的身份登录,而不需要用户名/密码。 (2认同)