来自跨域的请求之间的烧瓶会话不持久

flask sessions not persistent between requests from cross domains

我有一个前端 vue 站点托管在 google 的 firebase 上,使用 url (https://front-end.web.com) , while my flask backend is hosted on heroku with the url (https://back-end.heroku.com)。这使得我的会话不会跨请求持续存在,我尝试通过在我的后端实现 CORS 来解决这个问题,但由于某种原因它不起作用,下面是我的代码片段来展示我的实现

config_class.py

class ConfigClass():
    CORS_ALLOW_HEADERS = ['Content-Type']
    CORS_ORIGINS = ['https://front-end.web.com']
    SECRET_KEY = os.environ.get("APP_SECRET_KEY")
    SESSION_TYPE = 'redis'

_init.py

from flask import Flask, session
from flask_session import Session
from flask_cors import CORS


from root_folder.config import ConfigClass


db = SQLAlchemy() 
migrate = Migrate() 
ma = Marshmallow()  
sess = Session()


def create_app(ConfigClass):

    # initiate the flask app and assign the configurations #
    app = Flask(__name__)
    app.config.from_object(config_options[config_class])
    sess.init_app(app)

    from root_folder.clients import clients_app

    # register all the blueprints in this application
    app.register_blueprint(clients_app)

    CORS(app, supports_credentials=True)

    # return the app object to be executed
    return app

app.py

from root_folder import create_app

app = create_app()

过程文件:

web: gunicorn -w 1 app:app

axios前端请求

let formData = new FormData();
formData.append("email", email);
formData.append("password", password);

axios.post(
                backendUrl+'create_client_account',
                formData,
                {
                    withCredentials: true,
                    headers:{
                       "Content-Type": "multipart/form-data"
                    }
                }
);

创建客户端路由(我已将此代码块剥离到最低限度以使其易于理解):

from flask import session

# route for creating account credentials
@bp_auth_clients_app.route("/create_client", methods=["POST"])
def create_client():
    
    username = request.form.get("username").lower()
    email = request.form.get("email").lower()

    
    # create account code goes here  #
    
    auth_authentication = True

    session["auth_authentication"] = auth_authentication

    req_feedback = {
            "status": True,
            "message": "Account was successfully created",
            "data": feedback_data
    }

    return jsonify(req_feedback), 200

账号创建成功后,我在后续请求中无法访问session值,returns None.

为了在我的本地服务器上重现该问题,我通过域“localhost:8080”访问前端,同时通过“127.0.0.1:8000”访问 flask 服务器。如果我把前端域名改成“127.0.0.1:8080”,一般不会有什么问题。

请多多指教。

会话使用 cookie: 在 session 创建时,服务器将在 set-cookie header 中发送 cookie 值。由于跨源问题,它对您不起作用。

当你使用 127.0.0.1 时它工作正常,因为 127.0.0.1:8080127.0.0.1:8000 是同源的,所以浏览器接受 set-cookie header 和设置 cookie 没问题。

每个请求都在 header 中发送 Cookie,并且您的服务器通过 cookie 值从 Redis 加载 session(cookie 值称为 session_id)。
它是如何插入的 => 通常你的 session 在请求生命周期结束时被序列化并插入到 Redis 中,cookie 散列作为 Key。

如果您想继续使用 sessions 和 cookie,您需要为您的部署找到另一个解决方案,以便您的后端和前端具有相同的主机名。

如果您做不到,我建议您阅读有关 JWT (Json-Web-Tokens) 的内容。

编辑 您可以在响应中发送 session id body 并将其保存在本地存储中。

然后你需要配置: frontend 设置 session id 值它在 Authorization header base64 编码。 后端 base64 解码 Authorization header 来自请求的值并检查 Redis 中的 session,如果存在则加载它。

编辑

如何使用 apache 在同一主机名上部署两者 backend/frontend: 使用 apache 你需要创建 2 个虚拟主机,一个用于后端,另一个用于前端侦听不同的端口然后配置你的 web 服务器部署以使用后端 VH 如果路径以 /api/ 为前缀并将前端虚拟主机用于还要别的吗。 这样,您向 api 发出的任何请求都将由您的后端处理,否则它将为您的前端应用程序提供服务。 这只是一种方法,还有很多其他方法 Check this question.

感谢 Ahmad 的建议,我能够使用前端和后端的自定义域解决问题,如下所示:

frontend.herokuapp.com -> customDomain.com
backend.herokuapp.com -> api.customDOmain.com 

最后,我将以下行添加到我的会话配置中:

SESSION_COOKIE_DOMAIN = ".customDomain.com"

一切都很好。