【问题标题】:Flask: share sessions between domain.com and username.domain.comFlask:在 domain.com 和 username.domain.com 之间共享会话
【发布时间】:2014-08-15 10:36:27
【问题描述】:

我有一个烧瓶在 domain.com 上运行

我在 username.domain.com 上运行的另一台服务器上还有另一个烧瓶实例

一般用户通过 domain.com 登录

但是,对于付费用户,他们应该登录 username.domain.com

使用flask,我如何确保在domain.com 和username.domain.com 之间共享会话,同时确保它们只能访问特别匹配的username.domain.com?

我担心这里的安全问题。

【问题讨论】:

    标签: python flask subdomain


    【解决方案1】:

    编辑: 后来,在阅读了您的完整问题后,我发现原来的答案不是您想要的。

    我已将原版留在此答案的底部供 Google 员工使用,但修订版如下。

    Cookie 会自动发送到域中的子域(在大多数现代浏览器中,域名必须包含句点(表示 TLD)才能发生此行为)。身份验证需要作为预处理器进行,并且您的会话需要从集中式源进行管理。让我们来看看吧。

    为了确认,我将继续假设(根据您告诉我的)您的设置如下:

    • 服务器 1:
      • 适用于 domain.com 的 Flask 应用程序
    • 服务器 2:
      • 用于 username.domain.com 上的用户配置文件的 Flask 应用

    首先必须解决的一个问题是将会话存储在两个服务器都可以访问的位置。由于默认会话存储在磁盘上(显然两台服务器不共享同一个硬盘),我们需要对现有设置和新的 Flask 应用程序进行一些修改以用于用户配置文件。

    第一步是选择存储会话的位置,由 MySQL、Postgres 等 DBMS 提供支持的数据库是常见的选择,但人们也经常选择将它们放在更短暂的地方,例如 Memcachd 或 Redis例子。

    在这两个截然不同的系统之间进行选择的简短版本分为以下几点:

    数据库

    • 数据库一应俱全
    • 您可能已经实现了一个数据库
    • 开发人员通常对他们选择的数据库有预先的了解

    内存(Redis/Memchachd/等)

    • 相当快
    • 系统通常提供基本的数据自我管理功能
    • 不会对现有数据库产生额外负载

    您可以在flask herehere 中找到一些示例数据库会话。

    虽然根据每个用户的体验级别设置 Redis 会更加困难,但我建议使用它。你可以看到一个这样做的例子here

    我认为其余的都包含在原始答案中,其中一部分演示了用户名与数据库记录(较大的代码块)的匹配。

    单个 Flask 应用的旧解决方案

    首先,您必须设置 Flask 来处理子域,这就像在配置文件中指定新的变量名一样简单。例如,如果您的域是 example.com,您可以将以下内容附加到您的 Flask 配置中。

    SERVER_NAME = "example.com"
    

    您可以阅读有关此选项的更多信息here

    这里要注意的一点是,如果您只是在本地主机上工作,这将非常困难(如果不是不可能的话)。如上所述,浏览器通常不会费心将 cookie 发送到名称中没有点(TLD)的域的子域。本地主机也未设置为在许多操作系统中默认允许子域。有一些方法可以做到这一点,比如定义您自己的 DNS 条目,您可以查看这些条目(/etc/hosts 在 *UNIX 上,%system32%/etc/hosts 在 Windows 上)。

    准备好配置后,您需要为子域通配符定义 Blueprint

    这很容易做到:

    from flask import Blueprint
    from flask.ext.login import current_user
    
    # Create our Blueprint
    deep_blue = Blueprint("subdomain_routes", __name__, subdomain="<username>")
    
    # Define our route
    @deep_blue.route('/')
    def user_index(username):
    
        if not current_user.is_authenticated():
            # The user needs to log in
            return "Please log in"
        elif username != current_user.username:
            # This is not the correct user.
            return "Unauthorized"
    
        # It's the right user!
        return "Welcome back!"
    

    这里的技巧是确保您的用户对象的__repr__ 包含用户名键。比如……

    class User(db.Model):
    
        username = db.Column(db.String)
    
    
        def __repr__(self):
           return "<User {self.id}, username={self.username}>".format(self=self)
    

    需要注意的是,当用户名包含在 URL 中不起作用的特殊字符(空格、@、? 等)时会出现问题。为此,您需要对用户名实施限制,或者先正确转义名称并在验证时取消转义。

    如果您有任何问题或要求,请提出。这是在我喝咖啡休息时间做的,所以有点匆忙。

    【讨论】:

      【解决方案2】:

      您可以使用内置的 Flask 会话来执行此操作,这些会话是基于 cookie 的客户端会话。要允许用户登录 '.domain.com' 中的多个子域,您只需指定

       app.config['SESSION_COOKIE_DOMAIN'] = '.domain.com'
      

      并且客户端的浏览器将有一个会话 cookie,允许他登录到位于“domain.com”的每个 Flask 实例。 这仅在 Flask 的每个实例具有相同的 app.secret_key 时才有效

      有关详细信息,另请参阅 Same Flask login session across two applications

      【讨论】:

      • 非常感谢。您的回答很好。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-24
      • 2014-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多