2012-06-13 12 views
12

मैं चाहता हूं कि उपयोगकर्ता अपने ब्राउज़र में केवल एक टैब से अपनी साइट ब्राउज़ करें। यह कैसे किया जा सकता है? क्या मैं जावास्क्रिप्ट और कुकीज़ का उपयोग करूंगा?लोगों को अपनी वेबसाइट को कई टैब पर लोड करने से रोकें

उदाहरण के लिए, मैं एक वेबसाइट है: www.example.com - और मैं अपने ग्राहकों के लिए केवल एक ब्राउज़र में एक ही टैब से साइट पर जाएँ करने में सक्षम होना चाहता हूँ। यदि वे एक और टैब खोलते हैं और साइट (या साइट का उपपृष्ठ) लोड करते हैं - मुझे एक चेतावनी चाहिए "एकाधिक उदाहरण" नहीं खोल सकता है, और फिर उन्हें एक त्रुटि पृष्ठ पर रीडायरेक्ट कर सकते हैं।

एक बार बात नोट करने के लिए - उपयोगकर्ता www.example.com/action/door/mine.aspxwww.example.com करने से पता परिवर्तित करता है - वह ठीक से काम करना चाहिए, क्योंकि उपयोगकर्ता एक ही (मूल) टैब में है।

किसी भी मदद की सराहना की जाएगी। अग्रिम में धन्यवाद।

+0

वैसे आप एक छोटे जावास्क्रिप्ट हर अब और फिर एक दिल की धड़कन अनुरोध पोस्ट वर्तमान उपयोगकर्ता के सत्र आईडी के साथ, इससे पहले कि पृष्ठ लोड आप जाँच लें कि यह ajax दिल की धड़कन में आ रहा है हो सकता था इस सत्र के लिए, यदि यह है, तो आप इसे समाप्त कर देते हैं। – gideon

+2

आप इसे सीमित मामलों के लिए ऐसा करने में सक्षम हो सकते हैं, लेकिन आम तौर पर यह असंभव है।उपयोगकर्ता कुछ या सभी स्क्रिप्ट अक्षम कर सकते हैं, कुकीज़ और इतिहास तक पहुंच से इनकार कर सकते हैं, और कुछ ब्राउज़र एक टैब में पूरी तरह से नया सत्र शुरू करने की अनुमति देते हैं, इसलिए आईपी स्नीफिंग (जो सर्वर आसानी से कर सकता है) के अलावा आप भाग्य से बाहर हैं। – RobG

उत्तर

7

EDIT2:

यह सही बात जो this answer में उल्लेख किया गया है है, आप 2 आईडी की जरूरत है :

  1. एक यादृच्छिक एक
  2. एक सुसंगत एक (यह हमारे SSID वास्तव में हो जाएगा, के बाद से आप एक ही ब्राउज़र का टैब की सीमा है, यह उत्पन्न प्रपत्र ब्राउज़र की अद्वितीय पैरामीटर प्राप्त करने के लिए बेहतर है)

आप ब्राउज़र के उपयोगकर्ता-एजेंट से लगातार एक उत्पन्न या प्राप्त कर सकते हैं यह सर्वर से तरफ से। दोनों सर्वर-साइड स्टोर करें।
यादृच्छिक एक को window.name संपत्ति में स्टोर करें जो टैब-विशिष्ट है।
अपने सर्वर पर प्रत्येक 1 ~ 2 सेकंड दिल की धड़कन भेजें जिसमें लगातार आईडी और यादृच्छिक दोनों शामिल हैं। यदि सर्वर दिल की धड़कन प्राप्त करने में विफल रहता है, तो यह डेटाबेस को साफ़ करता है और मृत ग्राहकों को पंजीकृत करता है।
प्रत्येक ब्राउज़र के अनुरोध पर, मूल्य के लिए window.name देखें। यदि यह गुम हो गया था, तो सर्वर-साइड से जांचें कि क्या पिछला टैब बंद है या नहीं (डेटाबेस से साफ़ किया गया है)।

यदि हां, तो ग्राहक के लिए एक नई जोड़ी उत्पन्न करें यदि नहीं, तो उसे अस्वीकार कर दें। मेरे मन की चोटी पर


दो सुझाव:

  1. सर्वर साइड (बेहतर): अपने सभी ग्राहकों, एक उपयोगकर्ता नाम और पासवर्ड प्रदान करते हैं। उनके प्रमाण पत्र के साथ प्रवेश करने के लिए अपनी साइट की अपनी पहली यात्रा पर उनसे अनुरोध करें। फिर हर दूसरे अनुरोध पर, जांचें कि क्या कहा गया क्रेडेंशियल्स वाला उपयोगकर्ता पहले से लॉग इन है या नहीं।
 
    Client * 
     | 
     | 
     Server ---> Check whether 
        Already logged 
        or not? 
        ______________ 
        |   | 
        yes   no 
        |   | 
       permit  reject 
        him  him 
  1. क्लाइंट-साइड: आप वास्तव में इस का एक मजबूत की जांच की जरूरत है, evercookie का उपयोग ग्राहक की मशीन पर एक already-logged-in कुकी स्टोर करने के लिए।

साइड-ध्यान दें: पता है कि ग्राहक के पक्ष में हर प्रयास बिल्कुल सुरक्षित नहीं है! क्लाइंट-साइड को सर्वर-साइड की मदद करनी चाहिए, इसे सुरक्षा के एकमात्र स्रोत के रूप में उपयोग नहीं किया जाना चाहिए। even evercookies can be deleted तो, मेरा पहला सुझाव दें।


संपादित करें:

Evercookie वास्तव में कभी सबसे सुरक्षित ज़ोंबी कुकी संग्रहीत करने पर एक अच्छा काम कर रहा है लेकिन जब से पुस्तकालय में ही (ब्राउज़र के लिए एक छोटा सा भारी है एक कुकी संग्रहीत करने से अधिक 100ms प्रत्येक समय लगता है) वास्तविक दुनिया वेब ऐप में उपयोग करने के लिए वास्तव में इसकी अनुशंसा नहीं की जाती है।

उपयोग इन बजाय यदि आप सर्वर साइड समाधान के साथ चला गया:

+0

उत्तर के लिए धन्यवाद। कुछ सवाल । 1: सर्वर पक्ष, मैं उपयोगकर्ता के क्रेडेंशियल्स को स्टोर करने के लिए सत्र का उपयोग करता हूं और मेरे पास लॉग इन करने के लिए login.aspx पृष्ठ है, क्योंकि एक ब्राउज़र में टैब सत्र साझा करते हैं, इसलिए यदि मैं सिस्टम को एक टैब (टैबए) में लॉगिन करता हूं, और कॉपी करता हूं संपूर्ण यूआरएल (www.xx.com/some/test.aspx की तरह), और इसे किसी अन्य टैब (टैबबी) से खोलें, ब्राउजर उपयोगकर्ता को लॉग इन करेगा, और टैबबी में, यह login.aspx पेज पर रीडायरेक्ट नहीं होगा। अब मैं जांचता हूं कि क्या कभी भी इस समस्या को हल कर सकता है, उम्मीद है कि यह करता है, धन्यवाद – Jason

+0

@ जेसन नो! यदि आप सर्वर साइड सॉल्यूशन के साथ गए हैं, तो हमेशा केक्यूकी का उपयोग न करें, इसके बजाय इसका उपयोग करें: [एएसपी.NET सत्र के आस-पास कई टैब विंडोज़ में साझा किया जा रहा है] (http://stackoverflow.com/a/2839183/1055628)। evercookie बहुत ही सुरक्षित समाधान के लिए है, जैसे बैंकिंग और ऐसे (मेरे संपादित उत्तर को देखें)। – Sepehr

+0

धन्यवाद, "रास्ते के आसपास ..." का समाधान, क्या यह प्रत्येक टैब पेज को एक सत्र के रूप में बनाता है? मेरी समस्या को सीधे हल नहीं करें लेकिन किसी अन्य तरीके से? – Jason

1

क्यों क्या आप यह करना चाहते हैं?

कुछ बदसूरत हैकिंग करने का प्रयास कर सकता है, लेकिन परिणाम होगा: कोई तरीका है कि आप इस व्यवहार को पूरी तरह दबा सकते हैं।

यह जावास्क्रिप्ट द्वारा हल नहीं किया जा सका, क्योंकि हमेशा यह संभावना है कि उपयोगकर्ता ने अपने ब्राउज़र में जावास्क्रिप्ट को अक्षम कर दिया है, या केवल एक निश्चित सबसेट की अनुमति देता है।

उपयोगकर्ता एक बार में कई पृष्ठों पर जाने के लिए एक नया ब्राउज़र खोल सकता है, एक अलग कंप्यूटर का उपयोग कर सकता है।

लेकिन अधिक महत्वपूर्ण:

इसके अलावा, अपनी साइट केवल साइट इस व्यवहार और है कि हो सकता है इस कारण से यह हर किसी को भ्रमित करेंगे जो आपकी साइट का उपयोग करता है, क्योंकि यह एक वेब साइट की तरह काम नहीं करता है के लिए कार्य करना चाहिए। जो कोई दूसरा टैब खोलने का प्रयास करता है वह सोचता है: "यह अजीब है। यह वेबसाइट बेकार है क्योंकि यह अलग है तो वेबसाइटें होनी चाहिए। मैं फिर से नहीं आऊंगा!" ;-)

+2

धन्यवाद हिप्पो, क्योंकि हमारे एप्लिकेशन में क्लाइंट साइड से क्रियाओं को रिकॉर्ड करने के लिए लॉग सिस्टम जैसे कई फ़ंक्शन हैं, और कई टैब उपयोग किए जाने के साथ, सिस्टम भ्रमित हो जाएगा और यह नहीं पता कि वास्तव में क्या खुशी है, ट्रैक मुश्किल होगा, अगर जेएस अक्षम , ठीक है, हम इसके बारे में कुछ नहीं कर सकते हैं, यदि हां, तो वह हमारे सिस्टम का उपयोग नहीं कर सकता है। यह अजीब है, लेकिन दुर्भाग्य से हमें ऐसा करना है। – Jason

+0

आमतौर पर यदि सर्वर पर कुछ सत्र प्रबंधित किया जाता है और उपयोगकर्ता को दो विज़ार्ड एक साथ शुरू करने की अनुमति देने से कई टैब अक्षम करना आसान होता है। – otonglet

15

मैं इस के लिए एक सरल उपाय बना लिया है। मास्टर पेज लेआउट एक टैब GUID बनाता है और इसे टैब के सत्र स्टोरेज क्षेत्र में संग्रहीत करता है। स्टोरेज एरिया पर एक ईवेंट श्रोता का उपयोग करके मैं स्थानीय स्टोरेज क्षेत्र साइटों पर टैब GUID लिखता हूं। श्रोता तब टैब को GUID को साइट स्टोरेज में लिखे गए एक से तुलना करता है और यदि वे भिन्न होते हैं तो यह जानता है कि एक से अधिक टैब खुले हैं।

तो यदि मेरे पास तीन टैब ए, बी, सी हैं तो टैब सी में कुछ क्लिक करें, टैब ए और बी का पता लगाएं कि दूसरा टैब खुला है और इसके उपयोगकर्ता को चेतावनी दें। मुझे अभी तक इसे ठीक करने के लिए अभी तक नहीं मिला है, इसलिए आखिरी टैब का उपयोग अधिसूचना प्राप्त होता है, प्रगति पर काम करता है।

यहां मेरे जेएस में मास्टर पेज है, साथ ही लॉगिन पेज में मेरे पास पिछले सत्र से अंतिम टैब साफ़ करने के लिए localStorage.Clear है।

// multi tab detection 
function register_tab_GUID() { 
    // detect local storage available 
    if (typeof (Storage) !== "undefined") { 
     // get (set if not) tab GUID and store in tab session 
     if (sessionStorage["tabGUID"] == null) sessionStorage["tabGUID"] = tab_GUID(); 
     var guid = sessionStorage["tabGUID"]; 

     // add eventlistener to local storage 
     window.addEventListener("storage", storage_Handler, false); 

     // set tab GUID in local storage 
     localStorage["tabGUID"] = guid; 
    } 
} 

function storage_Handler(e) { 
    // if tabGUID does not match then more than one tab and GUID 
    if (e.key == 'tabGUID') { 
     if (e.oldValue != e.newValue) tab_Warning(); 
    } 
} 

function tab_GUID() { 
    function s4() { 
     return Math.floor((1 + Math.random()) * 0x10000) 
      .toString(16) 
      .substring(1); 
    } 
    return s4() + s4() + '-' + s4() + '-' + s4() + '-' + 
     s4() + '-' + s4() + s4() + s4(); 
} 

function tab_Warning() { 
    alert("Another tab is open!"); 
} 

ध्यान दें: यह IE9 +

आशा इस मदद करता है।

+0

धन्यवाद। verry cool solution –

+0

यह मेरे लिए काम नहीं कर रहा है। क्या मुझे किसी भी जेएस फ़ंक्शन को लोड पर कॉल करने की आवश्यकता है? –

+0

@DanielASathish कुमार सभी जेएस पेज में होना चाहिए और आपको पेज लोड पर register_tab_GUID() चलाया जाना चाहिए। – Darren

0

इसे हल करने का सबसे अच्छा तरीका एक बार सत्र आईडी होना है।

उदाहरण के लिए, प्रत्येक पृष्ठ में एक सत्र आईडी होती है, जो एक यात्रा के लिए मान्य है, अद्वितीय और यादृच्छिक है। किसी एक लिंक पर क्लिक करते समय, यह & का उपयोग करेगा सत्र आईडी को अमान्य कर देगा, और नए पृष्ठ में एक नया सत्र आईडी होगा।

यह उपयोगकर्ता को हमेशा नवीनतम विंडो या टैब में ब्राउज़ करने के लिए मजबूर करेगा, और तार पर सत्र चोरी को रोकता है। पुराने सत्र आईडी का पुन: उपयोग करने का कोई भी प्रयास तुरंत उस उपयोगकर्ता के सक्रिय सत्र आईडी को मारना चाहिए।

सत्र प्रबंधन प्रणाली में स्टोर करना भी महत्वपूर्ण है, पेज पेज से कौन से पृष्ठ पहुंच योग्य हैं। इसलिए यदि पृष्ठ एक्स (सत्र आईडी एबीसी के साथ) पृष्ठ 1, 2 और 3 के लिंक हैं, तो पेज 4 पर जाने का कोई भी प्रयास सत्र आईडी एबीसी के साथ, असफल हो जाएगा और सत्र को भी मार देगा।

यह उपयोगकर्ता को हमेशा एक सत्र सत्र ट्रैक करने के लिए मजबूर करेगा, और हमेशा साइट पर तर्क का पालन करेगा। इतिहास, लॉग का उपयोग करने, या एकाधिक विंडो या टैब खोलने, आगे बढ़ने का कोई भी प्रयास विफल हो जाएगा और सभी विंडोज़, टैब और डिवाइस में उपयोगकर्ता को लॉगआउट करेगा।

यह सब किसी भी क्लाइंट-साइड लॉजिक के बिना सर्वर-साइड पर पूरी तरह कार्यान्वित किया जा सकता है।

0

मैंने इसे कॉल सेंटर पेज को कई टैब में एक्सेस करने से रोकने के लिए लिखा था। यह अच्छी तरह से काम करता है और पूरी तरह क्लाइंट-साइड है। यदि आप एक नया टैब पता लगाते हैं तो आप जो चाहते हैं उसे करने के लिए बस else if भाग अपडेट करें।

// helper function to set cookies 
function setCookie(cname, cvalue, seconds) { 
    var d = new Date(); 
    d.setTime(d.getTime() + (seconds * 1000)); 
    var expires = "expires="+ d.toUTCString(); 
    document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; 
} 

// helper function to get a cookie 
function getCookie(cname) { 
    var name = cname + "="; 
    var decodedCookie = decodeURIComponent(document.cookie); 
    var ca = decodedCookie.split(';'); 
    for(var i = 0; i < ca.length; i++) { 
     var c = ca[i]; 
     while (c.charAt(0) == ' ') { 
      c = c.substring(1); 
     } 
     if (c.indexOf(name) == 0) { 
      return c.substring(name.length, c.length); 
     } 
    } 
    return ""; 
} 

// Do not allow multiple call center tabs 
if (~window.location.hash.indexOf('#admin/callcenter')) { 
    $(window).on('beforeunload onbeforeunload', function(){ 
     document.cookie = 'ic_window_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'; 
    }); 

    function validateCallCenterTab() { 
     var win_id_cookie_duration = 10; // in seconds 

     if (!window.name) { 
      window.name = Math.random().toString(); 
     } 

     if (!getCookie('ic_window_id') || window.name === getCookie('ic_window_id')) { 
      // This means they are using just one tab. Set/clobber the cookie to prolong the tab's validity. 
      setCookie('ic_window_id', window.name, win_id_cookie_duration); 
     } else if (getCookie('ic_window_id') !== window.name) { 
      // this means another browser tab is open, alert them to close the tabs until there is only one remaining 
      var message = 'You cannot have this website open in multiple tabs. ' + 
       'Please close them until there is only one remaining. Thanks!'; 
      $('html').html(message); 
      clearInterval(callCenterInterval); 
      throw 'Multiple call center tabs error. Program terminating.'; 
     } 
    } 

    callCenterInterval = setInterval(validateCallCenterTab, 3000); 
} 
1

मैं जानता हूँ कि इस पोस्ट बहुत पुराना है, लेकिन मामले में यह किसी को भी मदद करता है, मैं हाल ही में मूल रूप से एक ही बात localStorage और sessionStorage का उपयोग कर कर में देखा।

इसी तरह के Anthony's answer, यह सुनिश्चित करने के लिए एक अंतराल सेट करता है कि मूल टैब प्रविष्टि को ताजा रखता है, ताकि अगर ब्राउज़र क्रैश हो या अनलोड ईवेंट को कॉल किए बिना किसी भी तरह बंद हो जाए (टिप्पणियों में शामिल है लेकिन परीक्षण उद्देश्यों के लिए कोड का हिस्सा नहीं है), तो एक नई ब्राउज़र विंडो में एप्लिकेशन ठीक से चलने से पहले बस थोड़ी देर हो जाएगी।

जाहिर है, आप "टैब अच्छा है" बदल देंगे, "टैब खराब है" जो भी तर्क आप चाहते हैं उसे करने के लिए।

ओह, और साथ ही, createGUID विधि सत्र पहचानकर्ता अद्वितीय बनाने के लिए केवल एक उपयोगिता है ... यह this answer से पिछले प्रश्न पर है (यह सुनिश्चित करना चाहता था कि मैं इसके लिए क्रेडिट नहीं ले रहा था)।

https://jsfiddle.net/yex8k2ts/30/

let localStorageTimeout = 15 * 1000; // 15,000 milliseconds = 15 seconds. 
let localStorageResetInterval = 10 * 1000; // 10,000 milliseconds = 10 seconds. 
let localStorageTabKey = 'test-application-browser-tab'; 
let sessionStorageGuidKey = 'browser-tab-guid'; 

function createGUID() { 
    let guid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { 
    /*eslint-disable*/ 
    let r = Math.random() * 16 | 0, 
     v = c == 'x' ? r : (r & 0x3 | 0x8); 
    /*eslint-enable*/ 
    return v.toString(16); 
    }); 

    return guid; 
} 

/** 
* Compare our tab identifier associated with this session (particular tab) 
* with that of one that is in localStorage (the active one for this browser). 
* This browser tab is good if any of the following are true: 
* 1. There is no localStorage Guid yet (first browser tab). 
* 2. The localStorage Guid matches the session Guid. Same tab, refreshed. 
* 3. The localStorage timeout period has ended. 
* 
* If our current session is the correct active one, an interval will continue 
* to re-insert the localStorage value with an updated timestamp. 
* 
* Another thing, that should be done (so you can open a tab within 15 seconds of closing it) would be to do the following (or hook onto an existing onunload method): 
*  window.onunload =() => { 
       localStorage.removeItem(localStorageTabKey); 
     }; 
*/ 
function testTab() { 
    let sessionGuid = sessionStorage.getItem(sessionStorageGuidKey) || createGUID(); 
    let tabObj = JSON.parse(localStorage.getItem(localStorageTabKey)) || null; 

    sessionStorage.setItem(sessionStorageGuidKey, sessionGuid); 

    // If no or stale tab object, our session is the winner. If the guid matches, ours is still the winner 
    if (tabObj === null || (tabObj.timestamp < new Date().getTime() - localStorageTimeout) || tabObj.guid === sessionGuid) { 
    function setTabObj() { 
     let newTabObj = { 
     guid: sessionGuid, 
     timestamp: new Date().getTime() 
     }; 
     localStorage.setItem(localStorageTabKey, JSON.stringify(newTabObj)); 
    } 
    setTabObj(); 
    setInterval(setTabObj, localStorageResetInterval); 
    return true; 
    } else { 
    // An active tab is already open that does not match our session guid. 
    return false; 
    } 
} 

if (testTab()) { 
    document.getElementById('result').innerHTML = 'tab is good'; 
} else { 
    document.getElementById('result').innerHTML = 'tab is bad'; 
} 
संबंधित मुद्दे