Python中flask-login使用遇到的一些问题

flask-login 怎么确保用户登陆后,从异地登陆就会把上一次登陆的状态失效?


Python中flask-login使用遇到的一些问题
3 回复

Flask-Login这玩意儿用起来确实方便,但有几个坑得注意。我直接给你看个完整的例子,把常见问题都覆盖了。

from flask import Flask, render_template, redirect, url_for, request
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from werkzeug.security import generate_password_hash, check_password_hash

app = Flask(__name__)
app.secret_key = 'your-secret-key-here'  # 必须设置,不然session没法用

login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'  # 设置未登录时重定向的页面

# 模拟用户数据库
class User(UserMixin):
    def __init__(self, id, username, password_hash):
        self.id = id
        self.username = username
        self.password_hash = password_hash

# 模拟数据库查询
users_db = {
    1: User(1, 'admin', generate_password_hash('password123')),
    2: User(2, 'user', generate_password_hash('123456'))
}

@login_manager.user_loader
def load_user(user_id):
    """这个回调函数必须实现,用来从session中加载用户"""
    return users_db.get(int(user_id))

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        
        # 查找用户
        user = next((u for u in users_db.values() if u.username == username), None)
        
        if user and check_password_hash(user.password_hash, password):
            login_user(user, remember=True)  # remember参数实现"记住我"功能
            return redirect(url_for('dashboard'))
    
    return render_template('login.html')

@app.route('/dashboard')
@login_required  # 这个装饰器确保只有登录用户能访问
def dashboard():
    return f'欢迎回来, {current_user.username}!'

@app.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect(url_for('login'))

if __name__ == '__main__':
    app.run(debug=True)

关键点:1)@login_manager.user_loader回调必须正确实现,返回用户对象或None;2)User类要继承UserMixin,它提供了默认的is_authenticated等方法;3)login_user()调用后用户状态才会被记录;4)用@login_required保护需要登录的路由。

总结:仔细检查user_loader和用户对象的实现。


flask-login 中有个 Session Protection 机制,主要是针对 session 篡改或偷盗,默认有两种模式,basic 和 strong,默认是 basic 模式。这个机制的实现是这样的:每一个请求过来时,会针对用户端产生一个对应的标识符(一般是 hash(ip+user-agent)),如果这个 session 没有标识符,会做存储,如果有,比对成功的话,这个 request 就是成功的。basic 模式与 strong 模式区别在于:basic 模式下,如果发现 session 比对标识符不成功,这个 session 会被标记为 non-fresh,而在 strong 模式下,整个 session 直接删除

谢谢,I have figured it out。 我的解决方案是这样的,session 在请求上下文里是 client session,他会在处理后存在用户的 cookies 里面,而 login_user 操作会生成以登陆用户 ip 和 useragent 为原始数据的 sha256 字符串。存在 session[_id].

我的操作是在 login_user 操作后将当前登陆的时间写到 session 里面,并将登陆时间写到 server session (我是用的 mongodb ),因为以前登陆的用户的 session 中的登陆时间值是上次登陆的,,不匹配那就登陆状态失效喽。

回到顶部