烧瓶:domain.com和username.domain.com之间的共享会话

问题描述 投票:5回答:2

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

[我在另一个运行在username.domain.com的服务器上也有另一个flask实例

通常用户通过domain.com登录

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

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

我在这里担心安全性。

python flask subdomain
2个回答
5
投票

编辑:稍后,在阅读完您的完整问题后,我注意到原始答案不是您要的内容。

我将原始答案留在了答案的底部,留给了Google员工,但下面是修订版。

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

为了确认,我将假设您的设置如下:

    服务器1:
    • domain.com的Flask应用程序
  • 服务器2:
    • 用于用户配置文件的Flask应用程序,位于username.domain.com
  • 首先必须解决的问题是将会话存储在两台服务器均可访问的位置。由于默认情况下,会话存储在磁盘上(并且两台服务器显然不共享同一硬盘驱动器),因此我们需要对现有设置和用户资料的新Flask应用进行一些修改。

    [第一步是选择将会话存储在哪里,由DBMS(例如MySQL,Postgres等)支持的数据库是常见的选择,但是人们通常也会选择将它们放置在更短暂的地方,例如Memcachd或Redis。 。

    用于在这两个截然不同的系统之间进行选择的简短版本分解为以下内容:

    数据库

    • 数据库随时可用
    • 很可能您已经实现了数据库
    • 开发人员通常对其所选数据库已有知识
  • 内存(Redis / Memchachd / etc。]

    • 快很多
    • 系统通常提供基本的数据自我管理
    • 不会在现有数据库上产生额外的负载
  • 您可以在flask herehere中找到一些示例数据库会话。

    虽然根据每个用户的经验级别,Redis的设置会更加困难,但我建议选择此选项。您可以看到执行此操作的示例here

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

    单个Flask应用的旧解决方案

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

    SERVER_NAME = "example.com"

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

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

    一旦完成配置,就需要为子域通配符定义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中不起作用的特殊字符(空格,@ 、?等)时,会出现此问题。为此,您将需要对用户名实施限制,或者先适当地对名称进行转义,然后在验证时取消转义。

    如果您有任何疑问或要求,请询问。我在喝咖啡休息时间做了这个,所以有点着急。


    0
    投票
    您可以使用内置的Flask会话(基于Cookie的客户端会话)来执行此操作。要允许用户登录“ .domain.com”中的多个子域,只需指定
    © www.soinside.com 2019 - 2024. All rights reserved.