Подтвердить что ты не робот

Остановите людей, загружающих мой сайт на несколько вкладок

Я хочу, чтобы пользователи просматривали мой сайт только с одной вкладки в своем браузере. Как это может быть сделано? Я бы использовал javascript и куки?

Например, у меня есть веб-сайт: www.example.com - и я хочу, чтобы мои клиенты могли посещать сайт только с одной вкладки в одном браузере. Если они открывают другую вкладку и загружают сайт (или подстраницу сайта), я хочу получить предупреждение "Невозможно открыть несколько экземпляров", а затем перенаправить их на страницу с ошибкой.

Как только нужно отметить - если пользователь меняет адрес с www.example.com/action/door/mine.aspx на www.example.com - это должен работать нормально, потому что пользователь находится на одной и той же вкладке (оригинальной).

Любая помощь будет оценена. Спасибо заранее.

4b9b3361

Ответ 1

EDIT2:

Это точная вещь, о которой говорится в этом ответе, вам нужны 2 идентификатора:

  • Один случайный
  • Один последовательный (это будет наш SSID на самом деле, поскольку вы ограничиваете вкладки одного браузера, лучше получить сгенерированные уникальные параметры браузера)

Вы можете создать согласованный из пользовательского агента браузера или получить его с серверной стороны. храните их обоих на стороне сервера.
Храните случайное значение в window.name, которое зависит от табуляции.
Отправьте пульс каждые 1 ~ 2 секунды на ваш сервер, содержащий как согласованный идентификатор, так и случайный. если сервер не получает сердцебиение, он очищает базу данных и отменяет регистрацию мертвых клиентов.

в каждом запросе браузера отметьте window.name для значения. если он отсутствует, проверьте на стороне сервера, будет ли закрыта предыдущая вкладка или нет (очищено от базы данных).

Если да, сгенерируйте новую пару для клиента, если нет, отклоните его.


Два предложения на первый взгляд:
  • Серверная (лучше): предоставить всем своим клиентам, имя пользователя и пароль. попросите их при первом посещении вашего сайта ввести свои учетные данные. затем по каждому другому запросу проверьте, зарегистрирован ли пользователь с указанными учетными данными или нет.
  Client *
         |
         |
      Server ---> Check whether
                  Already logged
                     or not?
                  ______________
                   |          |
                  yes         no
                   |          |
                 permit     reject
                  him        him
  1. Клиентская сторона: Если вам действительно нужна сильная проверка, используйте evercookie для хранения already-logged-in cookie на клиентской машине.

Боковое примечание: Знайте, что каждая попытка на стороне клиента вообще не защищена! клиентская сторона должна помочь серверной стороне, она не должна использоваться как единственный источник безопасности. даже evercookies можно удалить, поэтому дайте моему первому предложению уйти.


EDIT:

Evercookie действительно хорошо справляется с хранением наиболее безопасных куки-зомби, но поскольку сама библиотека немного тяжела для браузеров (хранение файлов cookie занимает более 100 мс каждый раз), это не рекомендуется для использования в реальном мире веб-приложение.

используйте их вместо этого, если вы пошли с решением на стороне сервера:

Ответ 2

Я создал для этого простое решение. Макет главной страницы создает GUID вкладки и сохраняет его в области sessionStorage на вкладке. Используя прослушиватель событий в области хранения, я записываю GUID вкладки в область localStorage сайтов. Затем слушатель сравнивает GUID табуляции с тем, который записывается в хранилище сайта, и если они отличаются, то он знает, что открыто несколько вкладок.

Итак, если у меня есть три вкладки A, B, C, затем нажмите что-то на вкладке C, вкладки A и B обнаруживают, что открыта другая вкладка, и предупреждайте об этом. Мне еще не удалось его исправить, поэтому последняя используемая вкладка получает уведомление, работа продолжается.

Здесь у JS у меня есть главная страница, плюс на странице входа у меня есть 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 +

Надеюсь, что это поможет.

Ответ 3

Почему вы хотите сделать это?

Мог бы попытаться сделать некоторые уродливые взломы, но результат будет: Существует нет, чтобы вы могли полностью подавить это поведение.

Это не может быть разрешено JavaScript, потому что всегда существует вероятность того, что пользователь отключил JavaScript в своем браузере или разрешил только определенное подмножество.

Пользователь может открыть новый браузер, использовать другой компьютер и т.д., чтобы сразу посещать несколько страниц.

Но более важно:

Кроме того, ваш сайт будет единственным сайтом, который имеет такое поведение, и по этой причине это смутит всех, кто использует ваш сайт, потому что он не работает, как веб-сайт должен работать. Все, кто пытается открыть вторую вкладку, подумают: "Это странно. Этот сайт сосет, потому что он отличается от того, что должен быть на сайте. Я больше не приду!"; -)

Ответ 4

Я знаю, что этот пост довольно старый, но в случае, если он кому-то помогает, я недавно изучил в основном то же самое, используя localStorage и sessionStorage.

Подобный Anthony answer, он устанавливает интервал, чтобы убедиться, что вкладка-исходник сохраняет запись свежей, так что если браузер сбой или как-то закрывается, не вызывая событие разгрузки (включен в комментарии, но не является частью кода для целей тестирования), тогда будет просто небольшая задержка до того, как приложение будет работать должным образом в новом окне браузера.

Очевидно, вы изменили бы "вкладка хорошо", "вкладка плохая", чтобы выполнить любую логику, которую вы хотите.

О, а также метод createGUID - это просто утилита, которая делает уникальный идентификатор сеанса... от этого ответа к предыдущему вопросу (хотел убедитесь, что я не принимаю к сведению за это).

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

Ответ 6

Лучший способ решить это - иметь одноразовые идентификаторы сеанса.

Например, каждая страница содержит идентификатор сеанса, который действителен для одного посещения, является уникальным и случайным. При нажатии любой ссылки он будет использовать и аннулировать идентификатор сеанса, а новая страница будет иметь новый идентификатор сеанса.

Это заставит пользователя всегда просматривать в новом окне или вкладке, а также предотвращает кражу сеанса по проводу. Любая попытка повторного использования старого идентификатора сеанса должна немедленно убивать и активные идентификаторы сеанса для этого пользователя.

Также важно сохранить в системе управления сеансом, какие страницы доступны из страницы X. Поэтому, если страница X (с идентификатором сессии abc) содержит ссылки на страницы 1, 2 и 3, любая попытка посетить страницу 4 с помощью идентификатор сеанса abc, завершится с ошибкой и также завершится сеанс.

Это заставит пользователя всегда иметь один единственный трек сеанса и всегда следовать логике на сайте. Любая попытка перехода вперед, назад, использования истории или журнала или открытия нескольких окон или вкладок завершится с ошибкой и выйдет из системы во всех окнах, вкладках и устройствах.

Все это может быть полностью реализовано на стороне сервера без какой-либо клиентской логики.

Ответ 7

Я написал это, чтобы остановить доступ ко всей страницы колл-центра на нескольких вкладках. Он работает хорошо и чисто клиентский. Просто обновите часть 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 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);
}