【发布时间】:2011-03-31 15:36:04
【问题描述】:
请建议如何在 ASP.NET 中重新生成新的会话 ID。如果我们使用 SessionManager 来生成一个新的 id,那么它不会改变 Session.SessionID 的值。请建议如何实现这一点。基本上我想在放弃 Session 或用 SessionManager 生成 NewID 后有一个新的 Session.SessionID。
谢谢
【问题讨论】:
请建议如何在 ASP.NET 中重新生成新的会话 ID。如果我们使用 SessionManager 来生成一个新的 id,那么它不会改变 Session.SessionID 的值。请建议如何实现这一点。基本上我想在放弃 Session 或用 SessionManager 生成 NewID 后有一个新的 Session.SessionID。
谢谢
【问题讨论】:
看一下SessionIDManager.SaveSessionID 方法,它将新创建的会话标识符保存到 HTTP 响应中。:
SessionIDManager manager = new SessionIDManager();
var newId = manager.CreateSessionID(Context);
var isRedirected = false;
var isAdded = false;
manager.SaveSessionID(Current, newId, out isRedirected, out isAdded);
【讨论】:
web.config 中与会话相关的部分来扩展您的问题。我还想在manager.SaveSessionID 方法调用之后查看isRedirected 和isAdded 变量的值。
//Regenerate new Session ID after login
private void RegenerateSessionId()
{
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);
}
//get sessionId
string SessionId = HttpContext.Current.Session.SessionID; //new System.Web.SessionState.SessionIDManager().GetSessionID(Context);
【讨论】:
我们使用了 Alex 的解决方案,但最初它不起作用,返回了原始 sessionID,并且忽略了新生成的 sessionID。我们尝试了很多方法,最终奏效的是确保 sessionID 重新生成步骤位于任何登录步骤之外,并且步骤之间存在重定向。首先我们销毁会话 cookie,然后我们重新创建一个新的 sessionID,最后我们重定向到登录页面。任何登录前的重定向是关键步骤:
//delete session cookie
Session.Abandon();
Response.Cookies.Add(new HttpCookie("ASP.NET_SessionId", ""));
//create new sessionID
SessionIDManager manager = new SessionIDManager();
manager.RemoveSessionID(System.Web.HttpContext.Current);
var newId = manager.CreateSessionID(System.Web.HttpContext.Current);
var isRedirected = true;
var isAdded = true;
manager.SaveSessionID(System.Web.HttpContext.Current, newId, out isRedirected, out isAdded);
//redirect so that the response.cookies call above actually enacts
Response.Redirect("/account/logon");
【讨论】:
诀窍是在重定向之前在this.Session 中设置任何值,否则“空且因此无法使用的会话”将被回收。
下面的示例代码是我用来跨域共享一些会话相关信息的一些帮助函数的精简版本。首先进行服务器到服务器调用以设置会话 ID;其次,用户的浏览器被重定向到一个页面,该页面将设置会话 ID 并重定向到首页(或更相关的地方)。
private static string CreateSessionId(HttpContext httpContext)
{
var manager = new SessionIDManager();
string newSessionId = manager.CreateSessionID(httpContext);
return newSessionId;
}
public static void SetSessionId(HttpContext httpContext, string newSessionId, string redirect)
{
var manager = new SessionIDManager();
bool redirected;
bool cookieAdded;
manager.SaveSessionID(httpContext, newSessionId, out redirected, out cookieAdded);
// Just write anything to the session, so it isn't abandoned
httpContext.Session["WriteAnythingToTheSession"] = "Ok boss, consider it done!";
httpContext.Response.Redirect(redirect, true);
}
上面的测试是通过在正常页面周期的后期设置会话 ID,在Page_Load 中进行的。如果在 HttpHandler 或类似的东西中实现,可能会有所不同。此外,这是在旧版 ASP.NET 2.0 应用程序中实现的,并在 IIS Express 上进行了本地测试 - 您的情况可能会有所不同。
【讨论】: