2013-05-22 3 views
4

Я пытаюсь использовать Flask-KVSession в качестве альтернативной реализации сеанса для веб-сайта Flask. Я создал тестовый сайт (см. Код 1 ниже). Когда я запустил это, я могу использовать браузер для хранения значений в сеансе, перемещаясь между различными ресурсами в моем веб-браузере. Это работает правильно. Кроме того, когда я смотрю таблицу sessions в полученной базе данных SQLite, я вижу единственную запись, которая использовалась для хранения этого сеанса все время.Почему Flask-Security вызывает новую запись KVSession для каждого запроса?

Затем я пытаюсь добавить Flask-Security (см. Код 2 ниже). После запуска этого сайта (убедитесь, что сначала удалил существующий файл sqlite test.db), я попал в приглашение для входа в систему, и я вхожу в систему. Затем я перехожу к тому же, что и переключение между ресурсами. Я получаю те же результаты.

Проблема в том, что когда я смотрю в таблице sqlitebrowser sessions, есть 8 записей. Оказывается, новая запись сеанса была создана для каждого запрошенного запроса.

Почему создается новая запись сеанса для каждого запроса при использовании Flask-Security? Почему обновленная сессия не обновляется, как раньше?

Код 1 (KVSession без Колба-Security)

import os 
from flask import Flask, session 

app = Flask(__name__) 
app.secret_key = os.urandom(64) 
############# 
# SQLAlchemy 
############# 
from flask.ext.sqlalchemy import SQLAlchemy 

db = SQLAlchemy(app) 
DB_DIR = os.path.dirname(os.path.abspath(__file__)) 
DB_URI = 'sqlite:////{0}/test.db'.format(DB_DIR) 
app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI 

@app.before_first_request 
def create_user(): 
    db.create_all() 

############ 
# KVSession 
############ 
from simplekv.db.sql import SQLAlchemyStore 
from flask.ext.kvsession import KVSessionExtension 
store = SQLAlchemyStore(db.engine, db.metadata, 'sessions') 
kvsession = KVSessionExtension(store, app) 

@app.route('/a') 
def a(): 
    session['last'] = 'b' 
    return 'Thank you for visiting A!' 

@app.route('/b') 
def b(): 
    session['last'] = 'b' 
    return 'Thank you for visiting B!' 

@app.route('/c') 
def c(): 
    return 'You last visited "{0}"'.format(session['last']) 


app.run(debug=True) 

Code 2 (KVSession С Колба-Security)

import os 
from flask import Flask, session 

app = Flask(__name__) 
app.secret_key = os.urandom(64) 
############# 
# SQLAlchemy 
############# 
from flask.ext.sqlalchemy import SQLAlchemy 

db = SQLAlchemy(app) 
DB_DIR = os.path.dirname(os.path.abspath(__file__)) 
DB_URI = 'sqlite:////{0}/test.db'.format(DB_DIR) 
app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI 

########### 
# Security 
########### 
# This import needs to happen after SQLAlchemy db is created above 
from flask.ext.security import (
    Security, SQLAlchemyUserDatastore, current_user, 
    UserMixin, RoleMixin, login_required 
) 

# Define models 
roles_users = db.Table('roles_users', 
     db.Column('user_id', db.Integer(), db.ForeignKey('user.id')), 
     db.Column('role_id', db.Integer(), db.ForeignKey('role.id'))) 

class Role(db.Model, RoleMixin): 
    id = db.Column(db.Integer(), primary_key=True) 
    name = db.Column(db.String(80), unique=True) 
    description = db.Column(db.String(255)) 

class User(db.Model, UserMixin): 
    id = db.Column(db.Integer, primary_key=True) 
    email = db.Column(db.String(255), unique=True) 
    password = db.Column(db.String(255)) 
    active = db.Column(db.Boolean()) 
    confirmed_at = db.Column(db.DateTime()) 
    roles = db.relationship('Role', secondary=roles_users, 
          backref=db.backref('users', lazy='dynamic')) 

user_datastore = SQLAlchemyUserDatastore(db, User, Role) 
security = Security(app, user_datastore) 

@app.before_first_request 
def create_user(): 
    db.create_all() 
    user_datastore.create_user(email='[email protected]', password='password') 
    db.session.commit() 


############ 
# KVSession 
############ 
from simplekv.db.sql import SQLAlchemyStore 
from flask.ext.kvsession import KVSessionExtension 
store = SQLAlchemyStore(db.engine, db.metadata, 'sessions') 
kvsession = KVSessionExtension(store, app) 

@app.route('/a') 
@login_required 
def a(): 
    session['last'] = 'b' 
    return 'Thank you for visiting A!' 

@app.route('/b') 
@login_required 
def b(): 
    session['last'] = 'b' 
    return 'Thank you for visiting B!' 

@app.route('/c') 
@login_required 
def c(): 
    return 'You last visited "{0}"'.format(session['last']) 


app.run(debug=True) 

Version Info

Python 2.7.3 
Flask==0.9 
Flask==0.9 
Flask-KVSession==0.3.2 
Flask-Login==0.1.3 
Flask-Mail==0.8.2 
Flask-Principal==0.3.5 
Flask-SQLAlchemy==0.16 
Flask-Security==1.6.3 
SQLAlchemy==0.8.1 

ответ

6

Оказывается, это связано с known problem с flask-login (использование флагов), когда флажок-логин используется с библиотекой хранения сеансов, такой как KVSession.

В принципе, KVSession необходимо обновлять базу данных новой информацией о сеансе всякий раз, когда данные в сеансе создаются или изменяются. И в приведенном выше примере это происходит правильно: в первый раз, когда я нажимаю страницу, сеанс создается. После этого обновляется существующий сеанс.

Тем не менее, в фоновом режиме браузер отправляет на мой веб-сервер запрос cookie-запроса на поиск моего значка. Поэтому колба обрабатывает запрос до /favicon.ico. Этот запрос (или любой другой запрос, который будет 404) все еще обрабатывается колбой. Это означает, что флажок-логин будет смотреть на запрос и попытаться сделать свою магию.

Так получилось, что флажок-логин не пытается вставить что-либо в сеанс, но он все еще СМОТРЕТЬ, как сеанс был изменен в отношении KVSession. Поскольку он СМОТРЕТСЯ, как изменение сеанса, KVSession обновляет базу данных. Ниже приведен код из опоки-логин:

def _update_remember_cookie(self, response): 
    operation = session.pop("remember", None) 
    ... 

Метод _update_remember_cookie вызывается во время жизненного цикла запроса. Хотя session.pop не изменит сеанс, если в сеансе нет ключа «помнить» (который в этом случае нет), KVSession все еще видит поп и предполагает, что сеанс изменится.

Проблема для флажков-входа обеспечивает простое исправление ошибок, но оно не было введено в флэшку-логин.Похоже, что сопровождающий ищет полную переписку и реализует ее там.

 Смежные вопросы

  • Нет связанных вопросов^_^