zoukankan      html  css  js  c++  java
  • Flask 系列之 LoginManager

    说明

    • 操作系统:Windows 10
    • Python 版本:3.7x
    • 虚拟环境管理器:virtualenv
    • 代码编辑器:VS Code

    实验目标

    通过使用 flask-login 进行会话管理的相关操作,并完成用户合法性登陆和退出。

    安装

    pip install flask-login
    

    使用

    首先,在 todlistapp\__init__.py 中创建 login_manager,并进行相关配置,示例代码如下所示:

    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy
    from flask_bootstrap import Bootstrap
    from flask_login import LoginManager
    from config import Config
    
    app = Flask(__name__)
    app.config.from_object(Config)
    
    db = SQLAlchemy(app)
    bootstrap = Bootstrap(app)
    
    login_manager = LoginManager(app)
    login_manager.login_view = 'login'
    login_manager.login_message = '你必须登陆后才能访问该页面'
    login_manager.login_message_category = "info"
    
    from app import views
    

    然后,完善我们 todolistmodels.py 中关于用户密码校验部分的逻辑处理,示例代码如下所示:

    from app import db, login_manager
    from datetime import datetime
    from werkzeug.security import check_password_hash, generate_password_hash
    from flask_login import UserMixin, login_user
    
    
    @login_manager.user_loader
    def load_user(user_id):
        user = User.query.get(user_id)
        return user
    
    
    class User(db.Model, UserMixin):
        __tablename__ = 'users'
        # __table_args__ = {"useexisting": True}
    
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(20), nullable=False, unique=True)
        email = db.Column(db.String(120), nullable=False, unique=True)
        pwd = db.Column(db.String(120), nullable=False)
    
        things = db.relationship('Thing', backref='User', lazy='dynamic')
    
        def __repr__(self):
            return "<User %r>" % self.name
    
        def generate_password_hash(self, pwd):
            self.pwd = generate_password_hash(pwd)
    
        def check_password_hash(self, pwd):
            return check_password_hash(self.pwd, pwd)
    
    
    class Thing(db.Model):
        __tablename__ = 'things'
        # __table_args__ = {"useexisting": True}
    
        id = db.Column(db.Integer, primary_key=True)
        user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
        title = db.Column(db.String(20), nullable=False)
        text = db.Column(db.Text, nullable=False)
        add_date = db.Column(db.DateTime, default=datetime.now)
    
        def __repr__(self):
            return "<Todo %r>" % self.id
    

    然后在 todolistforms.py 中添加一个用于处理用户登陆的表单提交类,示例代码如下所示:

    from flask_wtf import FlaskForm
    from wtforms import StringField, SubmitField, TextAreaField, PasswordField
    from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError
    from models import User
    
    
    class RegisterForm(FlaskForm):
        username = StringField('用户名:', validators=[
                               DataRequired(), Length(min=6, max=20)])
        email = StringField('邮箱:', validators=[DataRequired(), Email()])
        pwd = PasswordField('密码:', validators=[
            DataRequired(), Length(min=8, max=120)])
        confirm = PasswordField('确认密码:', validators=[
                                DataRequired(), EqualTo('pwd')])
        submit = SubmitField('提交')
    
        def validate_username(self, username):
            user = User.query.filter_by(name=username.data).first()
            if user:
                raise ValidationError("用户昵称已存在。")
    
        def validate_email(self, email):
            user = User.query.filter_by(email=email.data).first()
            if user:
                raise ValidationError('邮箱已存在.')
    
    
    class LoginForm(FlaskForm):
        username = StringField('用户名:', validators=[
                               DataRequired(), Length(min=6, max=20)])
        password = PasswordField('密码:', validators=[DataRequired()])
        submit = SubmitField('登陆')
    
        def validate_username(self, username):
            user = User.query.filter_by(name=username.data)
            if not user:
                raise ValidationError('用户名不存在。')
    

    然后修改我们的 todolistappviews.py ,添加用户登陆和登出的路由处理函数,示例代码如下所示:

    from flask import render_template, redirect, url_for, flash
    from flask_login import login_user, login_required, current_user, logout_user
    from app import app, db
    from forms import RegisterForm, LoginForm
    from models import User
    
    
    @app.context_processor
    def inject_user():
        user = User.query.first()
        return dict(user=user)
    
    
    @app.route('/')
    @app.route('/index')
    def index():
        if not current_user.is_authenticated:
            return redirect(url_for('login'))
        return render_template('index.html', title="首页")
    
    
    @app.route('/login', methods=['POST', 'GET'])
    def login():
        form = LoginForm()
        if form.validate_on_submit():
            name = form.username.data
            pwd = form.password.data
            user = User.query.filter_by(name=name).first()
            if user and user.check_password_hash(pwd):
                login_user(user)
                flash('登陆成功。', category='info')
                return redirect(url_for('index'))
            else:
                flash("密码或账户错误。", category='error')
        return render_template('login.html', title='登录', form=form)
    
    
    @app.route('/logout')
    @login_required
    def logout():
        logout_user()
        flash('再见!')
        return redirect(url_for('login'))
    
    
    @app.route('/register', methods=['POST', 'GET'])
    def register():
        form = RegisterForm()
        if form.validate_on_submit():
            username = form.username.data
            email = form.email.data
            pwd = form.pwd.data
            user = User(name=username, email=email)
            user.generate_password_hash(pwd)
            db.session.add(user)
            db.session.commit()
            flash('注册成功', category='info')
            return redirect(url_for('login'))
        return render_template('register.html', title='注册', form=form)
    

    接着,修改我们 todolistapp emplateslogin.html 页面,添加用户登陆的表单,示例代码如下所示:

    {% extends 'base.html' %} {% block content %}
    <h1>登录页面</h1>
    {% from 'bootstrap/form.html' import render_form %} {{ render_form(form) }}
    {% endblock %}
    

    修改我们的 todolistapp emplates av.html 页面,完善菜单栏的逻辑控制,示例代码如下所示:

    <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <div class="container">
            <a class="navbar-brand" href="#">愿望清单</a>
    
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
                aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
    
            <div class="collapse navbar-collapse" id="navbarSupportedContent">
                <ul class="navbar-nav mr-auto">
                    <li class="nav-item {% if request.endpoint == 'index' %} active {% endif %}">
                        <a class="nav-link" href="{{ url_for('index') }}">首页<span class="sr-only">(current)</span></a>
                    </li>
                </ul>
    
                <ul class="navbar-nav">
                    {% if current_user.is_authenticated and user %}
                    <li class="nav-item {% if request.endpoint == 'logout' %} active {% endif %}">
                        <a class="nav-link" href="{{ url_for('logout') }}">登出</a>
                    </li>
                    {% else %}
                    <li class="nav-item {% if request.endpoint == 'login' %} active {% endif %}">
                        <a class="nav-link" href="{{ url_for('login') }}">登录</a>
                    </li>
                    <li class="nav-item {% if request.endpoint == 'register' %} active {% endif %}">
                        <a class="nav-link" href="{{ url_for('register') }}">注册</a>
                    </li>
                    {% endif %}
                </ul>
            </div>
        </div>
    </nav>
    

    修改我们的 todolistapp emplatesindex.html 页面,显示当前登陆的用户,示例代码如下所示:

    {% extends 'base.html' %} {% block content %}
    
    {% if current_user.is_authenticated and user %}
    <h1>{{ current_user.name }},欢迎回来</h1>
    {% else %}
    <h1>首页</h1>
    {% endif %}
    
    {% endblock %}
    

    此时,当我们运行起我们的网站后进入注册页面 http://127.0.0.1:5000 就可以进行用户的注册、登陆和登出了。

    参考连接

  • 相关阅读:
    C/C++动态链接
    通用makefile及解析(转)
    C指针
    C位处理
    C++重载操作符与转换
    吧唧下工作的事情 记用canvas封装的小小控件
    吧唧下工作的事情 平衡图控件
    银行卡验证正则
    element eltable和elpopover 最后一行的 elpopover 有时候点不开的问题
    'CONVERSION_EXIT_CUNIT_OUTPUT'(物料单位转换) SAP
  • 原文地址:https://www.cnblogs.com/hippieZhou/p/10603405.html
Copyright © 2011-2022 走看看