Apache上的Flask登录在几次点击和几次页面重新加载后将用户设置为匿名



注意:只有当我在Apache上运行带有WSGI的Flask时,才会出现此问题。当我通过flask run --host=0.0.0.0运行它时,我不会遇到任何问题。

我意识到还有许多其他问题与类似的问题,我尝试应用不同的建议,特别是以下建议:

设置:

login_user(form.user, remember=True, force=True)  # Tell flask-login to log them in.
session.permanent = True
app.permanent_session_lifetime = timedelta(seconds=3600)
session.modified = True

以及:app.config["REMEMBER_COOKIE_DURATION"] = timedelta(seconds=3600)

我在Apache 2.4和Python 3.6上运行Flask。

这是我的应用程序的代码:

import sys
import os
import os.path
import ssl
import json
from datetime import datetime, timedelta
from flask import Flask, make_response, url_for, render_template, jsonify, redirect, request, session
from flask_ldap3_login import LDAP3LoginManager
from flask_login import LoginManager, login_user, logout_user, UserMixin, current_user
from flask_security import login_required
from flask_session import Session
from flask_ldap3_login.forms import LDAPLoginForm
from ldap3 import Tls
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret'
app.config['DEBUG'] = True
# Hostname of your LDAP Server
app.config['LDAP_HOST'] = 'dc.website.com'
# Port number of your LDAP server
app.config['LDAP_PORT'] = 636
# Specify the server connection should use SSL
app.config['LDAP_USE_SSL'] = True
# Base DN of your directory
app.config['LDAP_BASE_DN'] = 'CN=Users,DC=website,dc=com'
# Users DN to be prepended to the Base DN
app.config['LDAP_USER_DN'] = ''
# Groups DN to be prepended to the Base DN
app.config['LDAP_GROUP_DN'] = ''
# The RDN attribute for your user schema on LDAP
app.config['LDAP_USER_RDN_ATTR'] = 'cn'
# The Attribute you want users to authenticate to LDAP with.
app.config['LDAP_USER_LOGIN_ATTR'] = 'sAMAccountName'
# The Username to bind to LDAP with
app.config['LDAP_BIND_USER_DN'] = 'CN=LDAP Read-only,CN=Users,DC=website,dc=com'
# The Password to bind to LDAP with
app.config['LDAP_BIND_USER_PASSWORD'] = 'password'
app.config["REMEMBER_COOKIE_DURATION"] = timedelta(seconds=3600)
login_manager = LoginManager(app)              # Setup a Flask-Login Manager
ldap_manager = LDAP3LoginManager(app)          # Setup a LDAP3 Login Manager.
# Initialize a `Tls` context, and add the server manually. See
# http://ldap3.readthedocs.io/ssltls.html for more information.
tls_ctx = Tls(
validate=ssl.CERT_REQUIRED,
version='ssl.PROTOCOL_TLSv1.3',
ca_certs_file='/usr/local/share/ca-certificates/cert.crt',
valid_names=[
'dc.website.com',
]
)
ldap_manager.add_server(
app.config.get('LDAP_HOST'),
app.config.get('LDAP_PORT'),
app.config.get('LDAP_USE_SSL'),
tls_ctx=tls_ctx
)
# Create a dictionary to store the users in when they authenticate
# This example stores users in memory.
users = {}

# Declare an Object Model for the user, and make it comply with the
# flask-login UserMixin mixin.
class User(UserMixin):
def __init__(self, dn, username, data):
self.dn = dn
self.username = username
self.data = data
def __repr__(self):
return self.dn
def get_id(self):
return self.dn

# Declare a User Loader for Flask-Login.
# Simply returns the User if it exists in our 'database', otherwise
# returns None.
@login_manager.user_loader
def load_user(id):
if id in users:
return users[id]
return None

# Declare The User Saver for Flask-Ldap3-Login
# This method is called whenever a LDAPLoginForm() successfully validates.
# Here you have to save the user, and return it so it can be used in the
# login controller.
@ldap_manager.save_user
def save_user(dn, username, data, memberships):
user = User(dn, username, data)
users[dn] = user
return user

# Declare some routes for usage to show the authentication process.
@app.route('/')
def home():
# Redirect users who are not logged in.
if not current_user or current_user.is_anonymous:
return redirect(url_for('login'))
return render_template('index.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
# Instantiate a LDAPLoginForm which has a validator to check if the user
# exists in LDAP.
form = LDAPLoginForm()
if form.validate_on_submit():
# Successfully logged in, We can now access the saved user object
# via form.user.
login_user(form.user, remember=True, force=True)  # Tell flask-login to log them in.
session.permanent = True
app.permanent_session_lifetime = timedelta(seconds=3600)
session.modified = True
return redirect('/')  # Send them home
return render_template('login.html', form=form, current_user=current_user)
@app.route('/logout')
def logout():
logout_user()
return redirect(url_for('login'))
if __name__ == '__main__':
app.run()

这是WSGI文件:

#!/usr/bin/python3.6
import logging
import sys
logging.basicConfig(stream=sys.stderr)
sys.path.insert(0, '/opt/flaskapp/')
from flaskapp import app as application
application.secret_key = 'secret'

有时用户会在几秒钟后注销,其他时候会话可能会持续一个小时。当我检查浏览器的内存(在Firefox、Chrome和Edge中)时,会话cookie仍然存在。

我做错什么了吗?我还尝试过检查users数组是否为空。确实如此。即使我在users = {}行之前进行某种try检查。

问题出在WSGI文件上,因为处理会话的是Apache。

应用程序代码中的app.permanent_session_lifetime = timedelta(seconds=3600)行实际上应该在WSGI文件中,因此它看起来应该是这样的:

#!/usr/bin/python3.6
import logging
import sys
from datetime import datetime, timedelta
logging.basicConfig(stream=sys.stderr)
sys.path.insert(0, '/opt/flaskapp/')
from flaskapp import app as application
application.secret_key = 'secret'
application.permanent_session_lifetime = timedelta(seconds=3600)

最新更新