Flask 会话在 Replit 中重定向后重置

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

我正在 Replit 中运行下面的 Flask 应用程序。当我在 MS Edge 或 Chrome 中运行它时,会话在重定向()后重置。当我在 Firefox 中运行它时它可以工作。这是代码:

from flask import Flask, render_template, request, redirect, url_for, session
import secrets

app = Flask(__name__)
app.secret_key = secrets.token_hex(16)

users = {
    'user1': {'username': 'user1', 'password': 'password1'},
    'user2': {'username': 'user2', 'password': 'password2'}
}

@app.route('/')
def home():
    print("loading home", session)
    return render_template('index.html')

@app.route('/signup', methods=['GET', 'POST'])
def signup():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        users[username] = {'username': username, 'password': password}
        return redirect(url_for('home'))
    return render_template('signup.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
    print("loading login", session)
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        user = users.get(username)
        if user and user['password'] == password:
            session['username'] = username
            print("session set", session)
            return redirect(url_for('home'))
    return render_template('login.html')

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080, debug=True)

这是控制台输出:

172.31.196.1 - - [21/Dec/2023 23:03:48] "OPTIONS * HTTP/1.1" 404 -
loading home <SecureCookieSession {}>
172.31.196.1 - - [21/Dec/2023 23:03:48] "GET / HTTP/1.1" 200 -
loading login <SecureCookieSession {}>
172.31.196.1 - - [21/Dec/2023 23:03:51] "GET /login HTTP/1.1" 200 -
loading login <SecureCookieSession {}>
172.31.196.1 - - [21/Dec/2023 23:03:51] "GET /login HTTP/1.1" 200 -
loading login <SecureCookieSession {}>
session set <SecureCookieSession {'username': 'user1'}>
172.31.196.1 - - [21/Dec/2023 23:04:06] "POST /login HTTP/1.1" 302 -
loading home <SecureCookieSession {}>
172.31.196.1 - - [21/Dec/2023 23:04:06] "GET / HTTP/1.1" 200 -
loading home <SecureCookieSession {}>
172.31.196.1 - - [21/Dec/2023 23:04:06] "GET / HTTP/1.1" 200 -

我已验证 cookie 已启用。

google-chrome flask firefox microsoft-edge replit
2个回答
0
投票

我已经更新了您的代码,以便在 Flask 中提供功能性的用户注册流程。当前代码使用字典中的

users
,我假设您将使用一些数据库来存储用户信息。

我添加了以下内容:

  • 注册完成后,在
    username
    中设置
    session
  • 在注册过程中添加了对具有相同用户名的现有用户的检查。
  • flash
    中设置必要的
    app.py
    消息并在模板中显示它们。
  • 添加了注销功能。

app.py

from flask import Flask, render_template, request, redirect, url_for, session, flash
import secrets

app = Flask(__name__)
app.secret_key = secrets.token_hex(16)

users = {
    'user1': {'username': 'user1', 'password': 'password1'},
    'user2': {'username': 'user2', 'password': 'password2'}
}


@app.route('/')
def home():
    username = session.get("username")
    return render_template('index.html', username=username)


@app.route('/logout')
def logout():
    session.pop('username', None)
    flash('You have been logged out.', 'info')
    return redirect(url_for('login'))


@app.route('/signup', methods=['GET', 'POST'])
def signup():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        if username not in users:
            flash('Account created successfully.', 'success')
            users[username] = {'username': username, 'password': password}
            session['username'] = username
            return redirect(url_for('home'))
        else:
            flash('Username already exists. Choose a different one.', 'error')
            print(f"Username {username} exists")
            return redirect(url_for('signup'))
    return render_template('signup.html')


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        user = users.get(username)
        if user and user['password'] == password:
            session['username'] = username
            flash('Logged in successfully.', 'success')
            return redirect(url_for('home'))
        else:
            flash('User not found. Try again.', 'error')
    return render_template('login.html')


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080, debug=True)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Home</title>
    <style>
        .error {
            color: red;
        }

        .success {
            color: green;
        }
    </style>
</head>
<body>
{% with messages = get_flashed_messages(with_categories=true) %}
    {% if messages %}
        <ul>
            {% for category, message in messages %}
                <li class="{{ category }}">{{ message }}</li>
            {% endfor %}
        </ul>
    {% endif %}
{% endwith %}

{% if username %}
    <p>Welcome, {{ username }}!</p>
    <a href="{{ url_for('logout') }}">Logout</a>
{% else %}
    <p>Not logged in. Please sign up or log in:</p>
    <a href="{{ url_for('signup') }}">Sign Up</a> | <a href="{{ url_for('login') }}">Login</a>
{% endif %}
</body>
</html>

signup.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sign Up</title>
    <style>
        .error {
            color: red;
        }

        .success {
            color: green;
        }
    </style>

</head>
<body>
{% with messages = get_flashed_messages(with_categories=true) %}
    {% if messages %}
        <ul>
            {% for category, message in messages %}
                <li class="{{ category }}">{{ message }}</li>
            {% endfor %}
        </ul>
    {% endif %}
{% endwith %}

<h2>Sign Up</h2>
<form method="post" action="{{ url_for('signup') }}">
    <label for="username">Username:</label>
    <input type="text" name="username" required><br>
    <label for="password">Password:</label>
    <input type="password" name="password" required><br>
    <input type="submit" value="Sign Up">
</form>
<p>Already have an account?
    <a href="{{ url_for('login') }}">Login</a>
</p>

</body>
</html>

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login</title>
    <style>
        .error {
            color: red;
        }

        .success {
            color: green;
        }
    </style>

</head>
<body>
{% with messages = get_flashed_messages(with_categories=true) %}
    {% if messages %}
        <ul>
            {% for category, message in messages %}
                <li class="{{ category }}">{{ message }}</li>
            {% endfor %}
        </ul>
    {% endif %}
{% endwith %}
<h2>Login</h2>
<form method="post" action="{{ url_for('login') }}">
    <label for="username">Username:</label>
    <input type="text" name="username" required><br>
    <label for="password">Password:</label>
    <input type="password" name="password" required><br>
    <input type="submit" value="Login">
</form>
<p>No account?
    <a href="{{ url_for('signup') }}">Sign Up</a>
</p>
</body>
</html>

演示

主页:

登录:

登录后主页:

参考文献


0
投票

解决了。问题在于基于 Chromium 的浏览器如何实现 RFC 2109(感谢 @davidism 的解释)。修复方法是使用以下代码设置 Set-Cookie 标头的 SameSite 和 Secure 属性:

app.config['SESSION_COOKIE_SAMESITE'] = 'None'
app.config['SESSION_COOKIE_SECURE'] = True
© www.soinside.com 2019 - 2024. All rights reserved.