来自跨域的请求之间的烧瓶会话不持久
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:8080
和 127.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"
一切都很好。
我有一个前端 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:8080
和 127.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"
一切都很好。