LoginSignup
8
6

More than 5 years have passed since last update.

[ASP.NET][IIS]別アプリケーション&別サーバでセッションを共有する方法

Last updated at Posted at 2019-01-18

IIS のセッション保存は、インプロセス(デフォルト)、SQL Server、ASP.NET 状態サービス(StateServer)が可能。
インプロセスではサーバー間でセッションは共有できないため、ここでは比較的導入が簡単なStateServerでの方法を記す。

StateServerでセッションを共有する場合、アプリケーション名、machineKey が一致& サイト間で同じCookiesを利用していればよい。
アプリケーション名はWeb.configだけで設定できないので、起動時に設定するように処理を追加する必要がある。
アプリケーション名が一致しない場合、セッションIDだけを共有でき、セッションデータは共有できない。

Web.configの設定

Web.config
<configuration>
  <system.web>
    <!-- Cookieを共有するサイトのドメインを指定-->
    <httpCookies domain=".your.site"/>
    <!-- セッション StateServerにセッション保存、セッションクッキー名の指定、タイムアウト指定-->
    <sessionState cookieless="UseCookies" cookieName="sessionXXXX" mode="StateServer" regenerateExpiredSessionId="false" stateConnectionString="tcpip=10.1.1.1:42424" timeout="30">
      <providers>
        <clear />
      </providers>
    </sessionState>
    <!-- machineKeyを設定-->
    <machineKey validationKey="B0577D3D82E341C0464C090C68681EC661DDB684E3B23166C7E8DE526490A5847152EE9EAA2928B89409FB4EB97F13BA12D11E6FABB4B8E3923364B496BA50FC" decryptionKey="93F24EC212137CC181B543FB8329C71810C351F76B0A2090CB9887811AC9DCC6" validation="SHA1" decryption="AES" /> 
  </system.web>
  <appSettings>
    <!-- アプリケーション名を設定-->
    <add key="ApplicationName" value="appName" />
  </appSettings>

</configuration>
  • Cookieを共有するサイトのドメインを指定。ドメインを広げすぎるとセキュリティ的に良くないので注意。
    ちゃんとやるなら、IIS ARRなどでリバースプロキシを用意して実施する。(リバースプロキシだと、1つのサーバにアクセスすればよいので、ドメイン指定しなくても同じCookieが使われる。)
  • セッション保存はsessionState 句にてStateServerを使うように指定。
    ASP.NET 状態サービス(StateServer)のデフォルトポートは42424.
    セッションクッキー名は、デフォルトのままでも良いが、ドメイン内で重複して他アプリへの影響も考慮し、設定。
  • MachineKeyは簡単に作れる Web サービスが公開されているので利用
    ASP.Net MachineKey Generator
    http://www.allkeysgenerator.com/Random/ASP-Net-MachineKey-Generator.aspx
  • アプリケーション名を指定。
    後ほど処理記述にて、このアプリケーション名をセットする。

ASP.NET 状態サービス(StateServer)の設定&起動

  • State Server のファイアウォールで TCP の 42424 ポートを許可
  • State Server のレジストリを修正 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\aspnet_state\ParametersAllowRemoteConnection1
  • 「ASP.NET 状態サービス」を無効=>自動に、起動。
    「ASP.NET 状態サービス」がレジストリ修正時に起動していたら再起動。
ConfigureStateServerRemote.cmd
Rem State Server のファイアウォールで TCP の 42424 ポートを許可
netsh advfirewall firewall add rule name="ASP .NET Session State Server" dir=in action=allow protocol=TCP localport=42424

Rem 現在の値を確認
Reg Query HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\aspnet_state\Parameters /v AllowRemoteConnection
Rem State Server のレジストリを修正 
Rem `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\aspnet_state\Parameters` の `AllowRemoteConnection` を `1` に変更
Reg Add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\aspnet_state\Parameters /v AllowRemoteConnection /t REG_DWORD /d 1 /f

Rem 現在の値を確認
Reg Query HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\aspnet_state\Parameters /v AllowRemoteConnection


Rem 「ASP.NET 状態サービス」を無効=>自動に
sc.exe config "aspnet_state" start=auto
sc stop "aspnet_state"
sc start "aspnet_state"

Global.asaxにてアプリケーション名を指定

Global.asax
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;

    public class Global : System.Web.HttpApplication
    {

        protected void Application_Start(object sender, EventArgs e)
        {
            ConfigureSession();
        }

        private void ConfigureSession()
        {
            // Get the app name from config file...
            string appName = System.Configuration.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 == "OutOfProcSessionStateStore")
                            {
                                FieldInfo uribaseInfo = storeType.GetField("s_uribase", BindingFlags.Static | BindingFlags.NonPublic);
                                uribaseInfo.SetValue(storeType, appName);
                            }
                        }
                    }
                }
            }
        }
    }

参照元

8
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
6