登录页面模板代码(登录页面模板打不开)

上一节我们已经创建了一个用户应用,并创建了用户模型,那么我们这节就开始实现一个简单的用户登录注册功能!

登录注册功能Flask有一个非常优秀的扩展Flask-login,我们可以选择使用这个扩展来实现,但为了学习我们暂时不使用这个第三方扩展,而是选择使用session来实现!

实现用户的登录功能

首先,我们需要完善登录的html页面, 路径为:app/auth/templates/login.html

{% extends 'base.html' %}

{% block title %} 登录页 {% endblock title %}

{% block hero %}{% endblock hero %}

{% block main %}
<div class="box is-radiusless is-marginless" style="height: 80%;">
    <div class="columns is-centered">
        <div class="column is-5-fullhd">
            {% block auth_form %}
            <form action="" method="post" style="margin-top: 40%;" class="box">
                <div class=" has-text-centered mb-3">
                    <p class=" subtitle">登录</p>
                    <h1 class="title">FlaskBlog</h1>
                </div>

                <!-- 消息闪现 -->
                {% with messages = get_flashed_messages() %}
                <b-message type="is-danger">
                  {% if messages %}
                    <ul class=flashes>
                    {% for message in messages %}
                        <li>{{ message }}</li>
                    {% endfor %}
                    </ul>
                {% endif %}
                </b-message>
                {% endwith %}

                <div class="field">
                    <p class="control has-icons-left has-icons-right">
                      <input class="input" type="text" name="username" id="id_username" maxlength="128" placeholder="Username">
                      <span class="icon is-small is-left">
                        <i class="fas fa-envelope"></i>
                      </span>
                      <span class="icon is-small is-right">
                        <i class="fas fa-check"></i>
                      </span>
                    </p>
                  </div>
                  <div class="field">
                    <p class="control has-icons-left">
                      <input class="input" type="password" name="password" id="id_password" maxlength="320" minlength="6" placeholder="Password">
                      <span class="icon is-small is-left">
                        <i class="fas fa-lock"></i>
                      </span>
                    </p>
                  </div>
                  <div class="field">
                    <p class="control">
                      <input class="button is-success is-fullwidth" type="submit" value="Login">
                    </p>
                </div>
            </form>
            {% endblock auth_form %}
        </div>

    </div>

</div>
{% endblock main %}

代码详解:

这个登陆模板继承了base.html的样式,这个base.html中的模块及代码其实就是我们之前实现的首页,只是我们把他作为一个模板基类来继承他!

这段代码中其实就是写了一个输入账号密码的表单,其他多余的代码都是为了实现表单的样式而存在的!

<input class="input" type="text" name="username" id="id_username" maxlength="128" placeholder="Username">
<input class="input" type="password" name="password" id="id_password" maxlength="320" minlength="6" placeholder="Password">

这里要特别说明的是这个input表单必须设置name属性,因为后端要根据此name属性来获取用户输入的值!其他属性则需要大家自行去了解学习!

登录功能的后端逻辑视图, 路径为:app/auth/views/auth.py

@bp.route('/login', methods=['GET', 'POST'])
def login():
    # 登录视图
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']

        error = None
        user = auth.User.query.filter_by(username=username).first()
        if user is None:
            error = '该用户不存在!'
        elif not check_password_hash(user.password, password):
            error = '密码不正确.'

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

代码详解: – request.method == 'POST'判断当前请求是否为post请求方式 – error = None 来初始化一个错误变量,如果未通过登录验证,把错误信息通过消息传送到页面提示用户

user = auth.User.query.filter_by(username=username).first()
if user is None:
    error = '该用户不存在!'
elif not check_password_hash(user.password, password):
    error = '密码不正确.'

这段代码首先在数据库通过用户提交的用户名去查询该用户,用户不存在就会返回None返回错误提示,用户存在则判断密码是否正确,这里用到了一个check_password_hash()的方法,这是用来将密文密码解密后与用户输入密码比对方法,与之对应的有一个generate_password_hash()的方法用来加密明文密码保存到数据库!

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

这段代码则是如果没有返回任何错误提示,说明该提交的表单符合我们的要求,并且数据库也存在该用户信息,那么我们只需要清空session,重新将session中的user_id设置为当前登录的id即可!

因此在实现登录注册逻辑之前就必须引入这两个方法:

from werkzeug.security import check_password_hash, generate_password_hash

登录功能虽然实现了,但我们数据库目前还没有任何一个用户,所以此时就应该要去实现用户的注册功能,向数据库新增用户,大概的逻辑是,用户输入用户名及两次密码,先判断该用户是否已经存在,存在则提示更换用户名,不存在则向数据库创建该用户信息,并清空session,重新设置user_id的值为注册用户的id,以达到注册成功后自动登录的目的!

实现用户的注册功能

首先,我们需要完善注册的html页面, 路径为:app/auth/templates/register.html

{% extends 'login.html' %}

{% block title %}注册{% endblock title %}

{% block auth_form %}
<form action="" method="post" style="margin-top: 40%;" class="box">
    <div class=" has-text-centered mb-3">
        <p class=" subtitle">注册</p>
        <h1 class="title">FlaskBlog</h1>
    </div>
     <!-- 消息闪现 -->
     {% with messages = get_flashed_messages() %}
     <b-message type="is-danger">
       {% if messages %}
         <ul class=flashes>
         {% for message in messages %}
             <li>{{ message }}</li>
         {% endfor %}
         </ul>
     {% endif %}
     </b-message>
     {% endwith %}

    <div class="field">
        <p class="control has-icons-left has-icons-right">
            <input class="input" type="text" name="username" id="id_username" maxlength="128" placeholder="Username">
            <span class="icon is-small is-left">
                <i class="fas fa-envelope"></i>
            </span>
            <span class="icon is-small is-right">
                <i class="fas fa-check"></i>
            </span>
        </p>
    </div>
    <div class="field">
        <p class="control has-icons-left">
            <input class="input" type="password" name="password" id="id_password" maxlength="320" minlength="6" placeholder="Password">
            <span class="icon is-small is-left">
                <i class="fas fa-lock"></i>
            </span>
        </p>
    </div>
    <div class="field">
        <p class="control has-icons-left">
            <input class="input" type="password" name="password1" id="id_password1" maxlength="320" minlength="6" placeholder="Password1">
            <span class="icon is-small is-left">
                <i class="fas fa-lock"></i>
            </span>
        </p>
    </div>
    <div class="field">
        <p class="control">
            <input class="button is-success is-fullwidth" type="submit" value="Register">
        </p>
    </div>
</form>
{% endblock auth_form %}

这是注册页面的html,大家自行理解下,这里着重说一个我们在视图中通过flash()传递出来的消息,在模板中由以下代码接收!

<!-- 消息闪现 -->
{% with messages = get_flashed_messages() %}
    <b-message type="is-danger">
    {% if messages %}
        <ul class=flashes>
            {% for message in messages %}
            <li>{{ message }}</li>
            {% endfor %}
        </ul>
    {% endif %}
    </b-message>
{% endwith %}

注册功能的后端逻辑视图, 路径为:app/auth/views/auth.py

@bp.route('/register', methods=['GET', 'POST'])
def register():
    # 注册视图
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        password1 = request.form['password1']

        if password != password1:
            flash('两次密码输入不一致!')
            return redirect(url_for('auth.register'))

        exists_user = auth.User.query.filter_by(username=username).first()
        if exists_user:
            flash('该用户名已经存在,请更换其他用户名!')
            return redirect(url_for('auth.register'))
        else:    
            user = auth.User(username=username, password=generate_password_hash(password))
            db.session.add(user)
            db.session.commit()
            session.clear()
            session['user_id'] = user.id
        return redirect(url_for('index'))
    return render_template('register.html')

这个注册的逻辑基本上涵盖了我们之前所有章节学到的知识点,这里就不再过多地去一一解释代码,大家可自行理解并完善注释!

实现用户退出登录功能

通过登录和注册功能的实现,我们已经清楚地知道,用户是否登录其实是判断session会话中是否存在用户的id来决定,那么推出登录,我们只需要清除session会话中的用户id即可,这里我们直接选择清空session的方式实现推出功能!

@bp.route('/logout')
def logout():
    # 注销
    session.clear()
    return redirect(url_for('index'))

在模板中获取用户信息

@bp.before_app_request
def load_logged_in_user():
    # 每个请求之前都回去session中查看user_id来获取用户
    user_id = session.get('user_id')
    if user_id is None:
        g.user = None
    else:
        g.user = auth.User.query.get(int(user_id))

bp.before_app_request()注册一个在视图函数之前运行的函数,无论请求什么 URL。 都会先检查用户 ID 是否存储在会话中,并从数据库获取该用户的数据,将其存储在 g.user 上,该数据在请求期间持续。

注册完这个函数之后,我们就可以在base.html中的导航的最右侧通过g.user的返回值,判断用户是否已经登录,显示不同的信息!

<!-- 导航 -->
{% block navbar %}     
<template>
    <b-navbar spaced shadow>
        <template #brand>
            <b-navbar-item>
                <img src="{{ url_for('blog.static', filename='img/logo.png') }}" alt="FlaskBlog">
            </b-navbar-item>
        </template>
        <template #start>
            <b-navbar-item href="#">
                Home
            </b-navbar-item>

        ... 省略部分代码
        </template>


        <template #end>
            <b-navbar-item tag="div">
                <!-- 判断用户是否已登录 -->
                {% if g.user %}              
                <div class=" buttons">
                    <!-- 获取用户信心 -->
                    <a class="button is-primary">欢迎您 {{ g.user['username'] }}</a>
                    <a class="button is-success">个人中心</a>
                    <!-- 显示推出按钮 -->
                    <a class="button is-danger" href="{{ url_for('auth.logout') }}">退出</a>
                </div>
                {% else %}
                <!-- 用户未登录,显示登录注册按钮 -->
                <div class="buttons">
                    <a class="button is-primary" href="{{ url_for('auth.register') }}">
                        <strong>Sign up</strong>
                    </a>
                    <a class="button is-light" href="{{ url_for('auth.login') }}">Log in</a>
                </div>
                {% endif %}
            </b-navbar-item>
        </template>
    </b-navbar>
</template>
{% endblock navbar %}
<!-- 导航 end -->             

实现login_required装饰器

对于像下一章节我们要实现的用户中心以及管理后台,则必须是带有权限的访问,最基本的权限应该是必须是登录用户,那么所以说对于那些未登录的用户我们需要拒绝访问的功能!

这个其实思路也非常简单,既然在实现模板中调用用户信息的时候,我们把当前登录的用户信息添加到了g对象,那么我们只需要判断g.user的返回值是否为None即可判断用户是否登陆!

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

到这里关于用户登录注册相关的基本权限问题我们就完成了,注意这些视图函数都在app/auth/views/auth.py文件中!

    
本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 cloud@ksuyun.com 举报,一经查实,本站将立刻删除。
如若转载,请注明出处:https://www.daxuejiayuan.com/45942.html