我想分享我的魔法。事实上,不,它还没有神奇。我们应该更多地测试和改进代码。
我只在 with-cookie、InProc 会话模式下测试了这些代码。将这些方法放入您的页面中,并在需要重新生成 ID 的位置调用它(请将您的 Web 应用程序设置为“完全信任”):
void regenerateId()
{
System.Web.SessionState.SessionIDManager manager = new System.Web.SessionState.SessionIDManager();
string oldId = manager.GetSessionID(Context);
string newId = manager.CreateSessionID(Context);
bool isAdd = false, isRedir = false;
manager.SaveSessionID(Context, newId, out isRedir, out isAdd);
HttpApplication ctx = (HttpApplication)HttpContext.Current.ApplicationInstance;
HttpModuleCollection mods = ctx.Modules;
System.Web.SessionState.SessionStateModule ssm = (SessionStateModule)mods.Get("Session");
System.Reflection.FieldInfo[] fields = ssm.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
SessionStateStoreProviderBase store = null;
System.Reflection.FieldInfo rqIdField = null, rqLockIdField = null, rqStateNotFoundField = null;
foreach (System.Reflection.FieldInfo field in fields)
{
if (field.Name.Equals("_store")) store = (SessionStateStoreProviderBase)field.GetValue(ssm);
if (field.Name.Equals("_rqId")) rqIdField = field;
if (field.Name.Equals("_rqLockId")) rqLockIdField = field;
if (field.Name.Equals("_rqSessionStateNotFound")) rqStateNotFoundField = field;
}
object lockId = rqLockIdField.GetValue(ssm);
if ((lockId != null) && (oldId !=null)) store.ReleaseItemExclusive(Context, oldId, lockId);
rqStateNotFoundField.SetValue(ssm, true);
rqIdField.SetValue(ssm, newId);
}
我一直在挖掘 .NET 源代码(可在http://referencesource.microsoft.com/netframework.aspx),并发现如果不破坏会话管理机制的内部结构,我就无法重新生成 SessionID。所以我就是这么做的 - 破解 SessionStateModule 内部字段,这样它将把当前的 Session 保存到一个新的 ID 中。也许当前的 HttpSessionState 对象仍然具有以前的 Id,但 AFAIK SessionStateModule 忽略了它。当它必须将状态保存在某处时,它只是使用内部 _rqId 字段。我尝试过其他方法,例如将 SessionStateModule 复制到具有重新生成 ID 功能的新类中(我计划用此类替换 SessionStateModule),但失败了,因为它当前引用了其他内部类(如 InProcSessionStateStore)。使用反射进行黑客攻击的缺点是我们需要将应用程序设置为“完全信任”。
哦,如果您确实需要 VB 版本,请尝试以下操作:
Sub RegenerateID()
Dim manager
Dim oldId As String
Dim newId As String
Dim isRedir As Boolean
Dim isAdd As Boolean
Dim ctx As HttpApplication
Dim mods As HttpModuleCollection
Dim ssm As System.Web.SessionState.SessionStateModule
Dim fields() As System.Reflection.FieldInfo
Dim rqIdField As System.Reflection.FieldInfo
Dim rqLockIdField As System.Reflection.FieldInfo
Dim rqStateNotFoundField As System.Reflection.FieldInfo
Dim store As SessionStateStoreProviderBase
Dim field As System.Reflection.FieldInfo
Dim lockId
manager = New System.Web.SessionState.SessionIDManager
oldId = manager.GetSessionID(Context)
newId = manager.CreateSessionID(Context)
manager.SaveSessionID(Context, newId, isRedir, isAdd)
ctx = HttpContext.Current.ApplicationInstance
mods = ctx.Modules
ssm = CType(mods.Get("Session"), System.Web.SessionState.SessionStateModule)
fields = ssm.GetType.GetFields(System.Reflection.BindingFlags.NonPublic Or System.Reflection.BindingFlags.Instance)
store = Nothing : rqLockIdField = Nothing : rqIdField = Nothing : rqStateNotFoundField = Nothing
For Each field In fields
If (field.Name.Equals("_store")) Then store = CType(field.GetValue(ssm), SessionStateStoreProviderBase)
If (field.Name.Equals("_rqId")) Then rqIdField = field
If (field.Name.Equals("_rqLockId")) Then rqLockIdField = field
If (field.Name.Equals("_rqSessionStateNotFound")) Then rqStateNotFoundField = field
Next
lockId = rqLockIdField.GetValue(ssm)
If ((Not IsNothing(lockId)) And (Not IsNothing(oldId))) Then store.ReleaseItemExclusive(Context, oldId, lockId)
rqStateNotFoundField.SetValue(ssm, True)
rqIdField.SetValue(ssm, newId)
End Sub