开发者

Regenerate SessionID in ASP.NET

开发者 https://www.devze.com 2023-02-20 21:29 出处:网络
Please suggest how to regenerate a new Session ID in ASP.NET. If we are using SessionM开发者_开发问答anager to generate a new id then it doesn\'t change the value of Session.SessionID. Please suggest

Please suggest how to regenerate a new Session ID in ASP.NET. If we are using SessionM开发者_开发问答anager to generate a new id then it doesn't change the value of Session.SessionID. Please suggest how this can be achieved. Basically I want to have a new Session.SessionID after abandoning Session or generating NewID with SessionManager.

Thanks


Take a look onto SessionIDManager.SaveSessionID method, it saves a newly created session identifier to the HTTP response.:

SessionIDManager manager = new SessionIDManager();
var newId = manager.CreateSessionID(Context);
var isRedirected = false;
var isAdded = false;
manager.SaveSessionID(Current, newId, out isRedirected, out 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);


We used Alex's solution but initially it did not work, the original sessionID returned and the newly generated sessionID was ignored. We tried a bunch of approaches and in the end what worked was to ensure the sessionID regeneration step sits outside any login step and that there is a redirect between steps. First we destroy the session cookie, then we recreate a new sessionID and lastly we redirect to the login page. The redirect before any log in is the critical step:

 //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");


The trick is to set any value in this.Session before redirecting, otherwise the "empty and therefor unusable session" will be recycled.

The example code below is the condensed version of some helper functions I'm using to share some session-related info across domains. First a server-to-server call is made to set up the session id; second the user's browser is redirected to a page that will set the session id and redirect to the front page (or somewhere more relevant).

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);
}

The above was tested by setting the session id late in the normal page cycle, in Page_Load. Might work differently if implemented in an HttpHandler or something like it. Also, this was implemented in a legacy ASP.NET 2.0 application and tested locally on IIS Express - your mileage may vary.


I thing, we need to make in this order:

  1. Generate a new SessionId with the SessionIdManager
  2. Save this new SessionId
  3. Set all variables attached to old session, to new session. Otherwise the session variables will be null in the new sessio

//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);
}
             

I tried adding this function and then calling it immediately done login, and it works for me.

Sources:

  • https://ujjwaladatta.wordpress.com/2016/11/23/regenerating-sessionid-in-asp-net/
  • https://thedotnetlight.wordpress.com/2020/07/03/regenerate-new-session-id-after-login/
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号