Django: поддерживать сессии в нескольких доменах - PullRequest
4 голосов
/ 19 июня 2019

У меня два / несколько доменов, скажем, foo.com и bar.com, и оба имеют одинаковый бэкэнд, что означает, что оба домена перенаправляют поступающие запросы на один и тот же «Веб-экземпляр» размещен в другом месте.


Текущее поведение

Если пользователь входит в систему foo.com, ему / ей также необходимо войти в систему bar.com, чтобы получить доступ к любой конечной точке / URL, например bar.com/some/url/end-point/.


SESSION_COOKIE_DOMAIN может что-то сделать, если у меня есть домены с общим шаблоном . К сожалению, нет.

Вопрос
Как я могу поддерживать сеансы пользователей в нескольких доменах?

Ответы [ 3 ]

2 голосов
/ 22 июня 2019

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

Теперь в большинстве случаев единственное, что вы хотели бы поделиться - это токен или идентификатор сеанса.Таким образом, вы можете подойти к этой проблеме по-разному

Перенаправление аутентификации

Предположим, ваш токен сгенерирован с использованием example.com/auth.Этот URL-адрес может возвращать токен в файлах cookie, а также ответ JSON.Затем вы также можете заставить этот URL возвращать 301 example.org/preauth?token=XXX.Этот URL затем установил бы куки с токеном

Так что, в принципе, в этом случае вы можете обрабатывать весь подход на самой стороне сервера

Используя пиксельные теги

В этомслучай, что вы хотите сделать, это URL-адрес тега пикселя.Как только вы получите токен авторизации, выполнив аутентификацию на example.com/auth

, вы добавите один тег источника изображения на страницу динамически, используя javascript, в ваш другой домен

<img src='http://example.org/cookiepixel?token=yyy' /> 

.файл cookie, который будет установлен в example.org вместо example.com

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

0 голосов
/ 23 июня 2019

Это интересный вопрос.Для этого должно быть много способов, первое, что приходит мне в голову, это использовать iframe.В приведенном ниже примере проверяется Django 2.2.

. В вашем settings.py выставьте sessionid на javascript.

SESSION_COOKIE_HTTPONLY = False

На ваш взгляд, обязательно поставьте xfram_options_exemptили django не разрешит "вставлять" его из другого домена, здесь я использую шаблонное представление, поэтому вместо этого я помещаю декоратор в urls.py.

from django.views.decorators.clickjacking import xframe_options_exempt

urlpatterns = [
    path(
        'other_domain/',
        xframe_options_exempt(TemplateView.as_view(template_name='examplesite/otherdomain.html')),
        name='other_domain',
    )
    # ...
]

domains - это списокиз всех других доменов (не включая тот, на котором сейчас находится ваш пользователь), в вашем шаблоне выставьте их в теге <head>.

<head>
    {{ domains|json_script:"domains" }}
    {{ other_domain_path|json_script:"other-domain-path"}}
</head>

это станет примерно так:

<script id="domains" type="application/json">["c222dbef.ngrok.io"] </script>
<script id="other-domain-path" type="application/json">"/other_domain/"</script>

Тогда в вашем javascript:

(function() {
  function getCookie(cname) { //copied from w3schools
    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 "";
  }

  function postSessionID(id) {
    var domains = JSON.parse(document.getElementById("domains").textContent);
    var path = JSON.parse(document.getElementById("other-domain-path").textContent);
    domains.forEach(function(domain) {
      var src = "https://" + domain + path;
      var iframeEl = document.createElement("iframe");
      iframeEl.setAttribute("class", "invisible");
      iframeEl.setAttribute("src", src);
      (function(id) { // this is an async call in a loop, create a closure here to protect "id"
        iframeEl.addEventListener("load", function() {
          this.contentWindow.postMessage(id, this.getAttribute("src"));
        });
      })(id);
      document.body.appendChild(iframeEl);
    });
  }

  function main() {
    var sessionID = getCookie("sessionid");
    if (!sessionID) {
      return;
    }
    postSessionID(sessionID);
  }

  main();

})();

Идея вышеприведенного кода заключается в создании iframes для доменов друг друга, src iframes указывает на наш view named "other_domain».После загрузки фреймов мы используем postMessage для отправки им идентификатора сессии.

В examplesite/otherdomain.html:

<head>
    {{ domains|json_script:"domains" }}
    {# we also need to expose all other domains #}
</head>

в вашем скрипте:

(function() {
  function setCookie(cname, cvalue, exdays) {
    var d = new Date();
    d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
    var expires = "expires=" + d.toUTCString();
    document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
  }
  var domains = JSON.parse(document.getElementById("domains").textContent);

  var trustedSources = domains.map(function(domain) {
    return "https://" + domain;
  });

  window.addEventListener("message", function(e) {
    if (!e.origin in trustedSources) {
      return; // this prevents setting session id from other source
    }
    var sessionID = e.data;
    // you can probably get your cookie expiry from your django view, so all of your cookie expires at the same time
    setCookie("sessionid", sessionID, 365);
  }, false);
})();

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

Я публикую полный пример в моем github: https://github.com/rabbit-aaron/django-multisite-sign-in

Выполните настройку readme.md.

0 голосов
/ 21 июня 2019

Я не думаю, что вы можете сделать единый вход для совершенно разных доменов.Но, возможно, вы могли бы использовать OAuth-аутентификацию , при этом оба домена указывают на одного и того же поставщика OAuth?Затем реализуйте OAuth-провайдер, который генерирует одинаковый токен доступа для любого домена.Я понятия не имею, сколько усилий может быть, хотя.

https://django -oauth-toolkit.readthedocs.io / en / latest /

...