13

这个问题的两个答案,取决于共享是跨不同站点还是不同子域第二个答案:多个 Django 应用程序,共享身份验证

用户访问 site1.com 并登录。现在,如果他访问 site2.com,那么他应该已经在该站点登录(经过身份验证)。

site1.com 和 site2.com 由同一服务器上的不同 Django 应用程序处理。

我知道这些站点可以共享包含身份验证表的数据库。我不明白的是如何处理会话数据。用户登录到site1 后,转到site2。在这里,他总是有 request.user = "AnonymousUser: AnonymousUser" 而不是 user_id。

我在这里设置它:https://docs.djangoproject.com/en/dev/topics/db/multi-db/

site1 的设置有一个包含身份验证模型以及其他一些数据表的数据库。site2 的设置有 2 个数据库。一个有自己的数据表,也是 user1 使用的一个。我基本上复制了类 AuthRouter 并设置了数据库路由器。

我想做的事不可能吗?我实际上并不了解这两个站点如何共享会话数据。我需要 Django 之外的东西吗?或者这应该工作吗?我可以在这里包含我的代码,但如果我对此的基本想法是错误的,我不想混淆这个问题。

编辑:这是我的设置。我正在本地主机上尝试这个。

Site1 在 localhost:8080 上运行

site2 在 localhost:8000 上运行

SITE2 应用程序:

db_router.py:

class AuthRouter(object):
    def db_for_read(self, model, **hints):
        if model._meta.app_label == 'auth':
            return 'the_ui'
        return None
    # same for write

    def allow_syncdb(self, db, model):
        if db == 'the_ui':
            return model._meta.app_label == 'auth'
        elif model._meta.app_label == 'auth':
            return False
        return None

class OtherRouter(object):
    def db_for_read(self, model, **hints):
        return "default"
    # same for write, relation, syncdb

设置.py:

DATABASE_ROUTERS = ['site2_app.db_router.AuthRouter', 'site2_app.db_router.OtherRouter']
SESSION_COOKIE_DOMAIN = 'http://localhost:8080'
SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies"

DATABASES = {
    'default': {
        # ...
    },
    'the_ui': {
        # ...
    }
}

站点 1 应用程序:

# no router
# only single database, same as the "the_ui" used in site2
SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies"
4

4 回答 4

20

根据使用不同站点的初始问题,标记的答案是正确的。

这是不同子域的答案,例如 www.site.com 和 shop.site.com

使用问题中描述的共享数据库身份验证。然后,在两个 settings.py 中:

SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies"
SESSION_COOKIE_DOMAIN = '.site.com' #notice the period
SESSION_COOKIE_NAME = 'my_cookie'
SECRET_KEY = "" the same in both settings.py

如果您有其他不应共享此信息的子域,则可能会出现一些问题。或者,也许不是,如果你给他们的饼干起不同的名字?

不确定这是否可以在本地主机上工作。

于 2013-08-15T08:10:07.620 回答
3

正如您所说,两个站点可以通过共享数据库或在各自数据库之间同步用户表来获得相同的身份验证数据。

这将确保 site1.com 的任何用户都将自动成为 site2.com 的成员,反之亦然。

但是您的要求 - 任何登录到 site1.com 的用户都应该自动登录到 site2.com 有点棘手。您真正需要的是单点登录 (SSO)。

为什么不能仅仅通过共享数据库(包括会话数据)来实现,因为由于跨域问题,site2.com 永远无法访问浏览器上 site1.com 设置的 cookie 。

有许多使用 Django 的 SSO 解决方案。看看这个SO question。虽然我从未使用过它,但Django-openid似乎是一个不错的选择。

于 2013-08-14T14:12:54.270 回答
0

您可以使用数据库路由器来指定应将哪个数据库用于身份验证后端。

在这里,我在下面给出了一个示例路由器代码:

class UserSessionRouter(object):

    def db_for_read(self, model, **hints):
        if model._meta.app_label == 'auth':
            return 'usersandsessions'
        elif model._meta.app_label == 'accounts':
            return 'usersandsessions'
        elif model._meta.app_label == 'sessions':
            return 'usersandsessions'
        return None

    def db_for_write(self, model, **hints):
        if model._meta.app_label == 'auth':
            return 'usersandsessions'
        elif model._meta.app_label == 'accounts':
            return 'usersandsessions'
        elif model._meta.app_label == 'sessions':
            return 'usersandsessions'
        return None

然后使用数据库设置DATABASE_ROUTERSSESSION_COOKIE_DOMAIN指定路由器,如下所示

DATABASE_ROUTERS = ['site2.routers.UserSessionRouter']
SESSION_COOKIE_DOMAIN = 'site1.com'
于 2013-08-14T12:24:10.757 回答
-1

正如 Sudipta 所说,openid 是完成 SSO 的一种方式。

另一种方法是直接使用 SAML(这里有一些工具),或者像 Stormpath ( https://stormpath.com ) 这样的托管服务,它为你做 SSO 的东西,并直接支持 Django 的身份验证系统:https ://github.com/stormpath/stormpath-django

我在 Stormpath 工作,非常有偏见,但我想我会插话,因为关于 SSO + Django 解决方案有很多困惑。

于 2014-12-12T21:41:56.310 回答