Flask 系列之 LoginManager

说明
- 操作系统:Windows 10
- Python 版本:3.7x
- 虚拟环境管理器:virtualenv
- 代码编辑器:VS Code
实验目标
通过使用 flask-login 进行会话管理的相关操作,并完成用户合法性登陆和退出。
安装
pip install flask-login
使用
首先,在 todlist\app\__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
然后,完善我们 todolist\models.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
然后在 todolist\forms.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('用户名不存在。')
然后修改我们的 todolist\app\views.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)
接着,修改我们 todolist\app\templates\login.html 页面,添加用户登陆的表单,示例代码如下所示:
{% extends 'base.html' %} {% block content %}
<h1>登录页面</h1>
{% from 'bootstrap/form.html' import render_form %} {{ render_form(form) }}
{% endblock %}
修改我们的 todolist\app\templates\nav.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>
修改我们的 todolist\app\templates\index.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 就可以进行用户的注册、登陆和登出了。
参考连接
Flask 系列之 LoginManager的更多相关文章
- Flask 系列之 部署发布
说明 操作系统:Windows 10 Python 版本:3.7x 虚拟环境管理器:virtualenv 代码编辑器:VS Code 实验目标 通过 Windows 的 WSL,将我们的项目网站部署到 ...
- 【Python】Flask系列-URL和视图笔记
1.学习目标 熟悉Flask相关知识. 熟悉web开发流程. 能独立开发Flask项目. 2.环境配置 Python虚拟环境安装 因为python的框架更新迭代太快了,有时候需要在电脑上存在一个框架的 ...
- Flask 系列之 优化项目结构
说明 操作系统:Windows 10 Python 版本:3.7x 虚拟环境管理器:virtualenv 代码编辑器:VS Code 实验目标 完善环境配置,添加 异常请求 处理 实现 400.404 ...
- Flask系列:数据库
这个系列是学习<Flask Web开发:基于Python的Web应用开发实战>的部分笔记 对于用户提交的信息,包括 账号.文章 等,需要能够将这些数据保存下来 持久存储的三种方法: 文件: ...
- Flask 系列之 Migration
说明 操作系统:Windows 10 Python 版本:3.7x 虚拟环境管理器:virtualenv 代码编辑器:VS Code 实验目标 通过使用 flask-migrate 实现数据库的迁移操 ...
- Flask 系列之 Blueprint
说明 操作系统:Windows 10 Python 版本:3.7x 虚拟环境管理器:virtualenv 代码编辑器:VS Code 实验目标 学习如何使用 Blueprint 介绍 接触过 DotN ...
- Flask 系列之 Pagination
说明 操作系统:Windows 10 Python 版本:3.7x 虚拟环境管理器:virtualenv 代码编辑器:VS Code 实验目标 实现当前登录用户的事务浏览.添加.删除 操作 实现 首先 ...
- Flask 系列之 FlaskForm
通过使用 FlaskForm ,可以方便快捷的实现表单处理. 说明 操作系统:Windows 10 Python 版本:3.7x 虚拟环境管理器:virtualenv 代码编辑器:VS Code 实验 ...
- Flask 系列之 Bootstrap-Flask
说明 操作系统:Windows 10 Python 版本:3.7x 虚拟环境管理器:virtualenv 代码编辑器:VS Code 实验目标 通过使用 Bootstrap-Flask 来进行页面美化 ...
随机推荐
- 像纸质笔记本一样给div,textarea添加行的分割线
想要给textarea添加一个背景图来实现 但是背景图有几个问题, 1.每个div或者textarea的line-height不一样,对于每个不同的line-height都需要一个不同的背景图 2.当 ...
- MySQL注入技巧性研究
0x00 前言 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品.MySQL 是最流行的关系型数据库管理系统之一,本人最近针对MySQL注入做了 ...
- DOS窗口查看端口占用
背景:最近用tomcat,一直访问不了,要账号密码登录,最后发现问题原因根本是tomcat的默认端口号8080被占用了,下面介绍如何通过dos窗口找到占用端口的进程. 方法: 打开DOS窗口,输入ne ...
- 使用yeoman搭建脚手架并发布到npm
前言 最近主要在写前端的模板类项目,由于其中的webpack配置和引进数据注入ejs模板的方法大同小异,所以萌发出把该模板框架提取出来作为一个常用的脚手架,也方便以后同事可以进行复用. 之前在看< ...
- onload事件与ready事件的区别,原生js与jquery的区别
onload事件与ready事件分别是原生js与jquery的入口函数 原生js入口函数写法: window.onload=function(){ } jquery入口函数写法: $(document ...
- HTML一些有趣的东西
1.<head>标签里: <meta http-equiv="Refresh" content="3"/><!--三秒自动刷新-- ...
- vue 项目实战 (生命周期钩子)
开篇先来一张图 下图是官方展示的生命周期图 Vue实例的生命周期钩子函数(8个) 1. beforeCreate 刚 new了一个组件,无法访问到数据和真实的do ...
- 使用 Helm 包管理工具简化 Kubernetes 应用部署
当在 Kubernetes 中已经部署很多应用时,后续需要对每个应用的 yaml 文件进行维护操作,这个过程会变的很繁琐,我们可以使用 Helm 来简化这些工作.Helm 是 Kubernetes 的 ...
- redis 系列4 数据结构之链表
一. 概述 链表提供了高效的节点重排能力,以及顺序性的节点访问方式,并且可能通过增删节点来灵活地调整链表的长度.作为一种数据结构,在C语言中并没有内置的这种数据结构.所以Redis构建了自己的链表实现 ...
- mysql 开发基础系列4 字符数据类型
字符串类型 1.1 CHAR 和VARCHAR 类型 CHAR 列的长度固定为创建表时声明的长度,VARCHAR 列中的值为可变长字符串.在检索的时候,CHAR 列删除了尾部的空格,而VARCHAR ...