2009-09-02 13 views
24

में एक नया एएसपी.NET सत्र उत्पन्न करना पाइपलाइन में हमारे कुछ उत्पादों के खिलाफ प्रवेश परीक्षा के परिणामस्वरूप, उस समय क्या होना चाहिए जब 'आसान' समस्या ठीक हो रही है toughy।वर्तमान HTTPContext

यह नहीं कि यह निश्चित रूप से होना चाहिए, मेरा मतलब है कि वर्तमान HTTPContext के लिए एक नया नया सत्र क्यों उत्पन्न करना इतना मुश्किल हो सकता है? विचित्र!


Imports System.Web 
Imports System.Web.SessionState 

Public Class SwitchSession 

    Public Shared Sub SetNewSession(ByVal context As HttpContext) 
     ' This value will hold the ID managers action to creating a response cookie 
     Dim cookieAdded As Boolean 
     ' We use the current session state as a template 
     Dim state As HttpSessionState = context.Session 
     ' We use the default ID manager to generate a new session id 
     Dim idManager As New SessionIDManager() 
     ' We also start with a new, fresh blank state item collection 
     Dim items As New SessionStateItemCollection() 
     ' Static objects are extracted from the current session context 
     Dim staticObjects As HttpStaticObjectsCollection = _ 
      SessionStateUtility.GetSessionStaticObjects(context) 
     ' We construct the replacement session for the current, some parameters are new, others are taken from previous session 
     Dim replacement As New HttpSessionStateContainer(_ 
       idManager.CreateSessionID(context), _ 
       items, _ 
       staticObjects, _ 
       state.Timeout, _ 
       True, _ 
       state.CookieMode, _ 
       state.Mode, _ 
       state.IsReadOnly) 
     ' Finally we strip the current session state from the current context 
     SessionStateUtility.RemoveHttpSessionStateFromContext(context) 
     ' Then we replace the assign the active session state using the replacement we just constructed 
     SessionStateUtility.AddHttpSessionStateToContext(context, replacement) 
     ' Make sure we clean out the responses of any other inteferring cookies 
     idManager.RemoveSessionID(context) 
     ' Save our new cookie session identifier to the response 
     idManager.SaveSessionID(context, replacement.SessionID, False, cookieAdded) 
    End Sub 

End Class 

यह काम करता है (कोड का प्रारूपण/पर प्रकाश डाला/विजुअल बेसिक मैं कुछ गलत कर किया जाना चाहिए के लिए क्षमा याचना): वैसे मैं करने के लिए एक मुखर छोटे उपयोगिता वर्ग "बस कर" लिखा है अनुरोध के शेष के लिए ठीक है, और सही ढंग से नए सत्र के रूप में स्वयं को पहचानता है (उदाहरण के लिए HTTPContext.Current.Session.SessionID नए जेनरेट किए गए सत्र पहचानकर्ता को वापस देता है)।

आश्चर्य आश्चर्य तब, जब अगले अनुरोध सर्वर हिट, HTTPContext.Session (एक HTTPSessionState वस्तु) सही SessionID साथ स्वयं का तादात्म्य है, लेकिन True करने के लिए IsNewSession सेट है, और, रिक्त है सब सत्र मूल्यों में सेट खोने पिछले अनुरोध

तो शुरुआती अनुरोध से हटाए गए पिछले HTTPSessionState ऑब्जेक्ट के बारे में कुछ खास होना चाहिए, यहां एक ईवेंट हैंडलर, एक कॉलबैक है, जो कुछ अनुरोधों पर सत्र डेटा को बनाए रखने में सक्षम है, या बस कुछ जो मुझे याद आ रहा है?

किसी को साझा करने के लिए कोई जादू मिला है?

+1

मैं इसे कुछ राज्य ('replacement' सत्र) और तारों के ऊपर सक्रिय ASP.NET अनुप्रयोग उदाहरण के लिए' SessionStateModule' घटनाओं देकर मेरी 'SwitchSession' वर्ग विकसित हुआ। जब 'स्टार्ट' ईवेंट आग लगती है, तो यह देखने के लिए जांच करता है कि क्या एएसपी.नेट के सत्र में सत्र 'सत्र आईडी' है और पिछले सत्र से सभी सत्र राज्य मानों की प्रतिलिपि बनाते हैं। जाहिर है केवल तभी काम करता है जब सभी अनुरोध 'HTTP अनुप्रयोग' उदाहरण के माध्यम से आते हैं जो पिछले अनुरोध को संभाला था। मैं 'सत्रस्टेट मॉड्यूल' में थोड़ा गहरा खोदने के लिए परावर्तक का उपयोग कर रहा हूं, लेकिन यह सुंदर नहीं है। कृपया इस सवाल को वोट दें! – Rabid

+0

मुझे आपके जैसा ही स्थान मिला है (RemoveHttpSessionStateFromContext के लिए खोज करके अपने पृष्ठ पर पहुंचे)। दुर्भाग्य से, आपके जैसा ही दीवार भी मारा - एक नया सत्र उत्पन्न नहीं हो सकता है। कुंजी निश्चित रूप से सत्रस्टेट मॉड्यूल है। कॉम्पलेटएक्वार्डस्टेट(), जो कि प्राप्त करना बेहद मुश्किल है - युधि का प्रतिबिंब दृष्टिकोण इसे प्राप्त करने का एक तरीका होगा, लेकिन मुझे यकीन नहीं है कि यह परेशानी के लायक है। मुझे यह कहना होगा कि जितना मुझे सी # पसंद है, .NET की एपीआई एक बड़ी निराशाजनक रही है - वे इसका खुलासा कैसे कर सकते हैं! – marq

+0

FYI: CompleteAququiredState() सत्र StateUtility.AddDelayedHttpSessionStateToContext() को कॉल करता है, जो एक नए सत्र के लिए सभी जादू करता है। – marq

उत्तर

32

मैं अपना जादू साझा करना चाहता हूं। असल में, नहीं, यह अभी तक जादुई नहीं है .. हमें कोड को और अधिक विकसित करना और विकसित करना चाहिए। मैंने इन कोडों को केवल-कुकी, इनप्रोक सत्र मोड में परीक्षण किया था। अपने पृष्ठ के अंदर इन विधि रखो, और यह कहते हैं जहां आईडी पुनर्जीवित करने की आवश्यकता है (पूर्ण ट्रस्ट के लिए अपने वेब एप्लिकेशन सेट करें):

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

मैं नेट स्रोत कोड के आसपास खुदाई की है (कि में उपलब्ध थे http://referencesource.microsoft.com/netframework.aspx), और पाया कि सत्र प्रबंधन तंत्र के आंतरिक को हैक किए बिना सत्र आईडी को पुन: उत्पन्न करने का कोई तरीका नहीं है। तो मैं बस यही करता हूं - सत्रस्टेट मॉड्यूल आंतरिक फ़ील्ड हैक करें, इसलिए यह मौजूदा सत्र को एक नई आईडी में सहेज देगा। हो सकता है कि वर्तमान HttpSessionState ऑब्जेक्ट में अभी भी पिछली आईडी है, लेकिन सत्र STATEModule AFAIK ने इसे अनदेखा किया। यह केवल आंतरिक _rqId फ़ील्ड का उपयोग करता है जब इसे कहीं और राज्य को सहेजना पड़ता है। मैंने अन्य तरीकों का प्रयास किया है, जैसे कि रीजननेट आईडी कार्यक्षमता के साथ सत्रस्टेट मॉड्यूल को एक नई कक्षा में कॉपी करना, (मैं इस वर्ग के साथ सत्रस्टेट मॉड्यूल को प्रतिस्थापित करने की योजना बना रहा था), लेकिन असफल रहा क्योंकि वर्तमान में इसमें अन्य आंतरिक वर्गों (जैसे InProcSessionStateStore) के संदर्भ हैं।प्रतिबिंब का उपयोग कर हैकिंग का नकारात्मक पक्ष हमें अपने आवेदन को 'पूर्ण ट्रस्ट' पर सेट करने की आवश्यकता है।

ओह, और यदि आप वास्तव में वीबी संस्करण की आवश्यकता है, इन की कोशिश:

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 
+1

आपके योगदान के लिए धन्यवाद, मेरा निष्कर्ष इसी तरह था, सत्र सत्र मॉड्यूल के मूल व्यवहार में छेड़छाड़ की आवश्यकता होगी। पूर्ण ट्रस्ट अनुमतियों की ऊंचाई एक शर्म की बात है, विशेष रूप से क्योंकि यह एक सुरक्षा समस्या को ठीक करना था (समस्या ई आईआईआरसी सत्र निर्धारण है)। अच्छा काम हालांकि :) – Rabid

+0

महान काम करता है। सत्र। सत्र आईडी शेष अनुरोध के लिए पुराने मूल्य को बरकरार रखता है। क्या कोई अपडेट है? –

+0

+1 और इस कोड के लिए एक गुच्छा धन्यवाद! मुझे वर्तमान संदर्भ से बनाए गए SimpleWorkerRequest पर HttpRuntime.ProcessRequest() का उपयोग करके एक बच्चे के अनुरोध को जन्म देने में कोई समस्या थी - अनुरोधों को गलत व्यवहार करना शुरू हुआ था यदि पिछले अनुरोध सत्र में लिखा था। बच्चे के अनुरोध निष्पादन कोड के दौरान आईडी स्विच करने के लिए अपने कोड का उपयोग उस समस्या को हल किया। – mawtex

0

क्या आपने HttpSessionState.Abandon method का उपयोग करने पर विचार किया है? यह सब कुछ साफ करना चाहिए। फिर एक नया सत्र शुरू करें और उपरोक्त कोड से संग्रहीत सभी वस्तुओं के साथ इसे पॉप्युलेट करें।

Session.Abandon(); पर्याप्त होना चाहिए। नहीं तो आप कुछ और कॉल के साथ अतिरिक्त प्रयास करने के लिए करता है, तो यह अभी भी जिद्दी किया जा रहा है की कोशिश कर सकते:

Session.Contents.Abandon(); 
Session.Contents.RemoveAll(); 
+3

दुर्भाग्यवश यह दृष्टिकोण उसी सत्र पहचानकर्ता का पुन: उपयोग करने के लिए प्रतीत होता है। मुझे जेनरेट करने के लिए एक नया सत्र पहचानकर्ता की आवश्यकता है :( – Rabid

0

तुम सिर्फ नहीं सेट कर सकता हूँ:

<sessionState regenerateExpiredSessionId="False" /> 
web.config में

, और फिर समाधान का उपयोग अहमद द्वारा सुझाया गया?

+3

दुर्भाग्यवश नहीं, यह अभी भी सक्रिय 'सत्र आईडी' को बरकरार रखता है, जो अगली अनुरोध हिट होने पर उपयोग किया जाता है। हालांकि इस संदर्भ में 'कालबाह्य' का अर्थ क्या है? सत्र समाप्त हो गया- मैं क्लाइंट कुकी की समाप्ति के अलावा सत्र की 'समाप्ति' करने का कोई तरीका नहीं देख सकता। यह मेरे सक्रिय 'HTTPContext' की मदद नहीं करता है। लेकिन अभी भी, इस विधि का उपयोग करने के बाद- मेरे पास सत्र छोड़ दिया और सभी सामग्रियों को हटा दिया, फिर मैं अपने उपयोगकर्ता को प्रमाणीकृत करता हूं और सत्र में कुछ जगह देता हूं, क्योंकि सत्र 'त्याग दिया गया' है, यह अगले अनुरोध पर खाली है। :(:(:( – Rabid

0

MVC4 के लिए कृपया इस कोड है: Can Gencer उल्लेख किया है

System.Web.SessionState.SessionIDManager manager = new System.Web.SessionState.SessionIDManager(); 
      HttpContext Context = System.Web.HttpContext.Current; 
      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)System.Web.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); 
+1

-1: यह http://stackoverflow.com/a/4420114/76337 से अलग कैसे है? –

1

- ReleaseItemExclusive वर्ष दूर नहीं करता स्टोर से सत्र और जो उस सत्र की ओर जाता है अंततः ग्लोबल.एक्सएक्स में सत्र_एंड को समाप्त और कॉल करता है। इससे हमें उत्पादन में बड़ी समस्या हुई, क्योंकि हम सत्र_इंड में थ्रेड पहचान को साफ़ कर रहे हैं, और इसके कारण - उपयोगकर्ता स्वचालित रूप से थ्रेड पर प्रमाणीकरण खो रहे थे।

तो नीचे सही कोड है जो काम करता है।

Dim oHTTPContext As HttpContext = HttpContext.Current 

Dim oSessionIdManager As New SessionIDManager 
Dim sOldId As String = oSessionIdManager.GetSessionID(oHTTPContext) 
Dim sNewId As String = oSessionIdManager.CreateSessionID(oHTTPContext) 

Dim bIsRedir As Boolean = False 
Dim bIsAdd As Boolean = False 
oSessionIdManager.SaveSessionID(oHTTPContext, sNewId, bIsRedir, bIsAdd) 

Dim oAppContext As HttpApplication = HttpContext.Current.ApplicationInstance 

Dim oModules As HttpModuleCollection = oAppContext.Modules 

Dim oSessionStateModule As SessionStateModule = _ 
    DirectCast(oModules.Get("Session"), SessionStateModule) 

Dim oFields() As FieldInfo = _ 
    oSessionStateModule.GetType.GetFields(BindingFlags.NonPublic Or _ 
             BindingFlags.Instance) 

Dim oStore As SessionStateStoreProviderBase = Nothing 
Dim oRqIdField As FieldInfo = Nothing 
Dim oRqItem As SessionStateStoreData = Nothing 
Dim oRqLockIdField As FieldInfo = Nothing 
Dim oRqStateNotFoundField As FieldInfo = Nothing 

For Each oField As FieldInfo In oFields 
    If (oField.Name.Equals("_store")) Then 
     oStore = DirectCast(oField.GetValue(oSessionStateModule), _ 
          SessionStateStoreProviderBase) 
    End If 
    If (oField.Name.Equals("_rqId")) Then 
     oRqIdField = oField 
    End If 
    If (oField.Name.Equals("_rqLockId")) Then 
     oRqLockIdField = oField 
    End If 
    If (oField.Name.Equals("_rqSessionStateNotFound")) Then 
     oRqStateNotFoundField = oField 
    End If 
    If (oField.Name.Equals("_rqItem")) Then 
     oRqItem = DirectCast(oField.GetValue(oSessionStateModule), _ 
          SessionStateStoreData) 
    End If 
Next 

If oStore IsNot Nothing Then 

    Dim oLockId As Object = Nothing 

    If oRqLockIdField IsNot Nothing Then 
     oLockId = oRqLockIdField.GetValue(oSessionStateModule) 
    End If 

    If (oLockId IsNot Nothing) And (Not String.IsNullOrEmpty(sOldId)) Then 
     oStore.ReleaseItemExclusive(oHTTPContext, sOldId, oLockId) 
     oStore.RemoveItem(oHTTPContext, sOldId, oLockId, oRqItem) 
    End If 

    oRqStateNotFoundField.SetValue(oSessionStateModule, True) 
    oRqIdField.SetValue(oSessionStateModule, sNewId) 

End If 
+0

मैक्स, क्या आप इसे सी # में अनुवाद कर सकते हैं? – vkelman

संबंधित मुद्दे