让你的flask先跑起来(四)

前文:https://blog.csdn.net/YouYuDeYan/article/details/121671059https://blog.csdn.net/YouYuDeYan/article/details/121671059

登录注册认证

Flaskr 有两个蓝图,一个用于认证功能,另一个用于博客帖子管理。每个蓝图的代码 都在一个单独的模块中。使用博客首先需要认证,因此我们先写认证蓝图。

flaskr/auth.py

import functools

from flask import (
    Blueprint, flash, g, redirect, render_template, request, session, url_for
)
from werkzeug.security import check_password_hash, generate_password_hash

from flaskr.db import get_db

bp = Blueprint('auth', __name__, url_prefix='/auth')

这里创建了一个名称为 'auth' 的 Blueprint 。和应用对象一样, 蓝图需要知道是在哪里定义的,因此把 __name__ 作为函数的第二个参数。 url_prefix 会添加到所有与该蓝图关联的 URL 前面。

使用 app.register_blueprint() 导入并注册 蓝图。新的代码放在工厂函数的尾部返回应用之前。

同样的,需要在flaskr/__init__.py注册,为简洁,后文如修改本文件,将从注释处开始代码展示

#已有代码
import os

from flask import Flask

from flaskr.setting import SECRET_KEY

def create_app(test_config=None):
    # create and configure the app
    app = Flask(__name__, instance_relative_config=True)
    app.config.from_mapping(
        #是被 Flask 和扩展用于保证数据安全的。在开发 过程中,为了方便可以设置为 'dev' ,但是在发布的时候应当使用 一个随机值来重载它。
        SECRET_KEY='!@#$%^&iewjqda(*^',
        DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
    )
    if test_config is None:
        # Load the instance config, if it exists, when not testing
        app.config.from_pyfile('config.py', silent=True)
    else:
        # Load the test config if passed in
        app.config.from_mapping(test_config)
    # ensure the instance floder exists
    try:
        os.makedirs(app.instance_path)
    except OSError:
        pass
    # a simple page that says hello
    @app.route('/hello')
    def hello():
        return 'Hello, World!'
    
    #数据库对象
    from . import db
    db.init_app(app)

#新增的函数代码

    #验证蓝图
    from . import auth
    app.register_blueprint(auth.bp)
 #后文对本文件修改将从此处开始展示代码
    


    return app

视图文件/注册

flaskr/auth.py

#已有代码
#验证蓝图
import functools

from flask import (
    Blueprint, flash, g, redirect, render_template, request, session, url_for
)
from werkzeug.security import check_password_hash, generate_password_hash

from flaskr.db import get_db

bp = Blueprint('auth', __name__, url_prefix='/auth')
#新增代码
#注册
#bp.route关联了 URL /register 和 register 视图函数。
#当 Flask 收到一个指向 /auth/register 的请求时就会调用 register 视图并把其返回值作为响应。
@bp.route('/register', methods=('GET', 'POST'))
def register():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        db = get_db()
        error = None

        if not username:
            error = 'Username is required.'
        elif not password:
            error = 'Password is required.'

        if error is None:
            try:
                db.execute(
                    "INSERT INTO user (username, password) VALUES (?, ?)",
                    (username, generate_password_hash(password)),
                )
                db.commit()
            except db.IntegrityError:
                error = f"User {username} is already registered."
            else:
                return redirect(url_for("auth.login"))

        flash(error)

    return render_template('auth/register.html')

这个 register 视图做了以下工作:

  1. @bp.route 关联了 URL /register 和 register 视图函数。当 Flask 收到一个指向 /auth/register 的请求时就会调用 register 视图并把其返回值作为响应。

  2. 如果用户提交了表单,那么 request.method 将会是 'POST' 。这咱情况下 会开始验证用户的输入内容。

  3. request.form 是一个特殊类型的 dict ,其映射了提交表单的键和值。表单中,用户将会输入其 username 和 password 。

  4. 验证 username 和 password 不为空。

  5. 如果验证成功,就把新用户的数据插入数据库。

    • db.execute 使用了带有 ? 占位符的 SQL 查询语句。占位符可以代替后面的元组参数中相应的值。使 用占位符的好处是会自动帮你转义输入值,以抵御 SQL 注入攻击 。

    • 因为安全原因,不能把密码明文储存在数据库中。而是应当使用 generate_password_hash() 生成安全的哈希值, 再把哈希值储存到数据库中。因为查询修改了数据,所以要使用 meth:db.commit() <sqlite3.Connection.commit> 保存修改。

    • 如果用户名已存在,会产生一个 sqlite3.IntegrityError 错误, 应当将该错误作为一个验证错误显示给用户。

  6. 用户数据保存后将转到登录页面。 url_for() 根据登录视图的名称生成相应的 URL 。与写固定的 URL 相比, 这样做的好处是如果以后需要修改该视图相应的 URL ,那么不用修改所有涉及到 URL 的代码。 redirect() 为生成的 URL 生成一个重定向响应。

  7. 如果验证失败,那么会向用户显示一个出错信息。 flash() 用于储存在渲染模块时可以调用的信息。

  8. 当用户最初访问 auth/register 时,或者注册出错时,应用显示一个注册 表单。 render_template() 会渲染一个包含 HTML 的模板,后文会展示html模板.

其中,账号密码验证前可以引用re库,正则匹配进行格式校验,正则的使用就不多赘述了,另外密码的加密建议使用不可逆加密方式,除了上文已介绍的,还可以使用md5包等进行加密

登录:

flaskr/auth.py,重点看login函数

#已有代码
#验证蓝图
import functools

from flask import (
    Blueprint, flash, g, redirect, render_template, request, session, url_for
)
from werkzeug.security import check_password_hash, generate_password_hash

from flaskr.db import get_db

bp = Blueprint('auth', __name__, url_prefix='/auth')

#注册
#bp.route关联了 URL /register 和 register 视图函数。
#当 Flask 收到一个指向 /auth/register 的请求时就会调用 register 视图并把其返回值作为响应。
@bp.route('/register', methods=('GET', 'POST'))
def register():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        db = get_db()
        error = None

        if not username:
            error = 'Username is required.'
        elif not password:
            error = 'Password is required.'

        if error is None:
            try:
                db.execute(
                    "INSERT INTO user (username, password) VALUES (?, ?)",
                    (username, generate_password_hash(password)),
                )
                db.commit()
            except db.IntegrityError:
                error = f"User {username} is already registered."
            else:
                return redirect(url_for("auth.login"))

        flash(error)

    return render_template('auth/register.html')

#新增代码
#登录
@bp.route('/login', methods=('GET', 'POST'))
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        db = get_db()
        error = None
        user = db.execute(
            'SELECT * FROM user WHERE username = ?', (username,)
        ).fetchone()

        if user is None:
            error = 'Incorrect username.'
        elif not check_password_hash(user['password'], password):
            error = 'Incorrect password.'

        if error is None:
            session.clear()
            session['user_id'] = user['id']
            return redirect(url_for('index'))

        flash(error)

    return render_template('auth/login.html')

#后文将从此开始代码

原理与注册相近,不过sql语句由插入insert变为select查询是否存在且正确.

与 register 有以下不同之处:

  1. 首先需要查询用户并存放在变量中,以备后用。

    fetchone() 根据查询返回一个记录行。 如果查询没有结果,则返回 None 。后面还用到 fetchall() ,它返回包括所有结果的列表。

  2. check_password_hash() 以相同的方式哈希提交的 密码并安全的比较哈希值。如果匹配成功,那么密码就是正确的。

  3. session 是一个 dict ,它用于储存横跨请求的值。当验证 成功后,用户的 id 被储存于一个新的会话中。会话数据被储存到一个 向浏览器发送的 cookie 中,在后继请求中,浏览器会返回它。 Flask 会安全对数据进行 签名 以防数据被篡改。

现在用户的 id 已被储存在 session 中,可以被后续的请求使用。 请每个请求的开头,如果用户已登录,那么其用户信息应当被载入,以使其可用于 其他视图。

session

既然已经有了session,我们就需要对其应用

flaskr/auth.py

#上文结束点
#本文开始点..
@bp.before_app_request
def load_logged_in_user():
    user_id = session.get('user_id')

    if user_id is None:
        g.user = None
    else:
        g.user = get_db().execute(
            'SELECT * FROM user WHERE id = ?', (user_id,)
        ).fetchone()

#下文开始点

这里上下文的代码就简洁展示,此处主要功能是用于校验是否已登录,当切换界面则无需再次登录

注销

注销的时候需要把用户 id 从 session 中移除。 然后 load_logged_in_user 就不会在后继请求中载入用户了。

#上文代码结束点
#本文开始点
@bp.route('/logout')
def logout():
    session.clear()
    return redirect(url_for('index'))

#下文代码开始点

点击注销后就需要重新登陆了.

当然不仅如此,你甚至可以设置session的有效期,有些网站你会发现你打开登陆后,放置一段时间就需要再次登录,就是session被清除了,使用任务或redis等可以轻松实现,但本文不做详解.

其他视图如果也需要登录才可以查看的话,可以做如下配置

flaskr/auth.py

def login_required(view):
    @functools.wraps(view)
    def wrapped_view(**kwargs):
        if g.user is None:
            return redirect(url_for('auth.login'))

        return view(**kwargs)

    return wrapped_view

引用该装饰器即可(如果不懂装饰器的可以了解下)

下文地址:

https://blog.csdn.net/YouYuDeYan/article/details/122080528icon-default.png?t=LA92https://blog.csdn.net/YouYuDeYan/article/details/122080528

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值