千哥读书笔记:《Flask2+Vue.js实战派》第6章第120页代码解析

第6章的内容,主要讲的是“用户认证和权限管理——基于Flask-Login库”的内容,在第120页,例出了一个通过创建LoginManager实例,实现用户登录认证的例子,代码位于配套资源的“ch06/6.1/app.py”中,可以通过下载地址:https://pan.baidu.com/s/1WSvlR4qT0fcxVzksto6mtg
提取码: aabb,进行下载。

“ch06/6.1/app.py”的源代码如下:

from flask import Flask, render_template, request, redirect, url_for
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required

app = Flask(__name__)
app.secret_key = '11223344'

# 实例化登录管理器对象
login_manager = LoginManager(app)
login_manager.login_view = 'login'
login_manager.session_protection="strong"
login_manager.login_message="欢迎回来"


# 定义用户模型
class User(UserMixin):
    def __init__(self, id,username,password):
        self.id = id
        self.username=username
        self.password=password

# 用户认证的回调函数
@login_manager.user_loader
def load_user(user_id):
    curr_user=User(1,"admin", "123456")
    return curr_user

# 显示登录表单
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form["password"]
        if username == "admin" and password == "123456":
            user = load_user("1")
            print(user)
            login_user(user)
            return redirect(url_for('index'))
        return "用户登录失败"
    return render_template('login.html')


# 显示主页
@app.route('/index')
@login_required
def index():
    return render_template('index.html')


# 用户注销
@app.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect(url_for('login'))


1、当未经登录的用户访问/index时,会触发@login_required装饰器。@login_required装饰器的作用是检查用户是否已经登录,如果用户未登录,它会根据LoginManager的配置来处理这种情况。在代码中,login_manager.login_view  = 'login',这意味着当检测到用户未登录时,会将用户重定向到名为login的路由,也就是@app.route('/login',  methods=['GET', 'POST'])。

2、当未经登录的用户访问/login时,在登录界面填入用户名和密码(admin和123456)提交之后,会显式地调用 load_user("1")这个函数,在获得用户信息之后,通过login_user(user),将用户信息通过cookie保存session,此时,Flask-Login 会通过login_user(user)自动调用用户对象(User 类实例)的 get_id() 方法。该方法返回一个字符串类型的用户标识符(例如"1")。这个返回值会被加密后存储在Cookie中。

3、login_user(user) 的内部机制:当调用 login_user(user) 时,Flask-Login 会通过 getattr(user, current_app.login_manager.id_attribute) 间接调用用户对象的 get_id() 方法,将返回的用户标识符(如用户 ID)加密后存储到会话(Session)中1。这一过程对开发者透明,无需手动操作。

4、当用户已登录时,访问/index时,@login_required装饰器会检查用户是否已登录。如果已登录,Flask-Login 需要从会话(Session)中恢复用户对象以验证身份。

而会话中如果存在 user_id ,Flask-Login 会自动调用 @login_manager.user_loader 装饰的回调函数 load_user(user_id)。在Flask-Login中,load_user(user_id)函数的user_id参数是由Flask-Login框架自动从用户的会话(Session)中提取的。

5、但这里存在一个问题,在下面的代码中:

# 用户认证的回调函数
@login_manager.user_loader
def load_user(user_id):
    curr_user=User(1,"admin", "123456")
    return curr_user

由于User(1,"admin", "123456")采取的是硬编码,也就是在User这个模型中,直接给出用户数据(1,"admin", "123456"),这会导致无论传入load_user(user_id)的值是多少,始终会让返回的返回的 User 对象的 id 始终是 1,username 始终是 "admin",password 始终是 "123456"。

6、而在有数据库支持的情况下,下面的代码:

# 用户认证的回调函数
@login_manager.user_loader
def load_user(user_id):
    curr_user=User(user_id,"admin", "123456")
    return curr_user

# 显示登录表单
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form["password"]
        if username == "admin" and password == "123456":
            user = load_user("1")
            print(user.get_id())
            login_user(user)
            return redirect(url_for('index'))
        return "用户登录失败"
    return render_template('login.html')

应该改为:

# 用户认证的回调函数

@login_manager.user_loader
def load_user(user_id):
    return User.query.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 = User.query.filter_by(username=username).first()
        
        # 验证用户存在且密码正确
        if user and user.check_password(password):
            login_user(user)  # 自动处理 user_id
            return redirect(url_for('index'))
        return "登录失败"
    return render_template('login.html')

也就是说,不应该采取硬编码的方式。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值