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\Parameters
のAllowRemoteConnection
を1
に - 「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);
}
}
}
}
}
}
}
参照元
- Sharing session between two asp.net web applications
http://www.freshcodehub.com/Article/48/sharing-session-between-two-aspnet-web-applications - Share Session between two web sites using asp.net and state server
https://stackoverflow.com/questions/3438912/share-session-between-two-web-sites-using-asp-net-and-state-server - リモートの State Server に接続するためのメモ
http://kendik.hatenablog.com/entry/2013/05/16/002108