背景
flask如何将部分页面鉴权后才能访问,笔者通过Flask-login实现,下面一起来看看是如何实现的吧。
系统环境
- win-11
- python 3.8
依赖安装
pip install flask
pip install flask-login
pip install flask-sqlalchemy
pip install sqlalchemy-utils
pip install click
pip install Werkzeug
页面展示
登录页面
登陆后页面
导入bootstrap依赖 和 html页面
# 新一个文件夹
# 新文件夹下创建staice文件夹用于存放bootstrap依赖,文件夹下再创建三个文件夹为:css、js、images
# 新文件夹下创建templates文件夹用于存放html文件
# 相关文件请通过云盘下载
# 文件目录结构
├─static
│ ├─css
│ ├─images
│ └─js
├─templates
配置app.py文件
导入相关模块,定义secrets 并配置ORM
from flask import Flask, render_template, request, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import LoginManager, login_user, login_required, logout_user, UserMixin
import sqlalchemy_utils
import os
import sys
import click
app = Flask(__name__)
'''
自动生成secret
import secrets
print(secrets.token_hex(32))
'''
app.secret_key = b'12313123131241414141241fsfgsfsdfsfs'
# 判断系统类型
WIN = sys.platform.startswith('win')
if WIN: # 如果是 Windows 系统,使用三个斜线
prefix = 'sqlite:///'
else: # 否则使用四个斜线
prefix = 'sqlite:'
# sqlite:///数据库文件的绝对地址,如果你使用 Windows 系统只需要写入三个斜线(即 sqlite:///)
app.config['SQLALCHEMY_DATABASE_URI'] = prefix + os.path.join(app.root_path, 'data.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # 关闭对模型修改的监控
db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
user_type = db.Column(db.String(255))
username = db.Column(db.String(255))
password_hash = db.Column(db.String(128)) # 密码散列值
def set_password(self, password): # 用来设置密码的方法,接受密码作为参数
self.password_hash = generate_password_hash(password) # 将生成的密码保持到对应字段
def validate_password(self, password): # 用于验证密码的方法,接受密码作为参数
return check_password_hash(self.password_hash, password) # 返回布尔值
定义手动创建管理用户模块
# 使用 click.option() 装饰器设置的两个选项分别用来接受输入用户名和密码。执行 flask admin 命令,输入用户名和密码后,即可创建管理员账户。
@app.cli.command()
@click.option('--username', prompt=True, help='The username used to login.')
@click.option('--password', prompt=True, hide_input=True, confirmation_prompt=True, help='The password used to login.')
def admin(username, password):
"""Create user."""
# 判断数据库是否存在
if sqlalchemy_utils.functions.database_exists(prefix + os.path.join(app.root_path, 'data.db')):
print('Database already exists.')
else:
print('Create database.')
db.create_all()
if db.session.query(User.id).filter_by(username=username).scalar() is not None:
user = User.query.filter_by(username=username).first()
click.echo('Updating user...')
user.set_password(password) # 设置密码
else:
click.echo('Creating user...')
user = User(username=username, user_type='Admin')
user.set_password(password) # 设置密码
db.session.add(user)
db.session.commit() # 提交数据库会话
click.echo('Done.')
创建与更新管理用户
定义登录与退出函数
通过@login_required 装饰器保护相应模块
@login_manager.user_loader
def load_user(user_id): # 创建用户加载回调函数,接受用户 ID 作为参数
user = User.query.get(int(user_id)) # 用 ID 作为 User 模型的主键查询对应的用户
return user # 返回用户对象
@app.route('/', methods=['GET', 'POST'])
@login_required # 用于视图保护
def index():
if request.method == "GET":
return render_template('index.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if not username or not password:
flash('Invalid input.')
return redirect(url_for('login'))
user = User.query.filter_by(username=username).first()
# 验证用户名和密码是否一致
if username == user.username and user.validate_password(password):
login_user(user) # 登入用户
# flash('Login success.')
return redirect(url_for('index')) # 重定向到主页
flash('Invalid username or password.') # 如果验证失败,显示错误消息
return redirect(url_for('login')) # 重定向回登录页面
return render_template('login.html')
@app.route('/logout')
@login_required
def logout():
logout_user() # 登出用户
flash('Goodbye.')
return redirect(url_for('login')) # 重定向回首页
完整app.py 文件
from flask import Flask, render_template, request, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import LoginManager, login_user, login_required, logout_user, UserMixin
import sqlalchemy_utils
import os
import sys
import click
app = Flask(__name__)
app.config['SECRET_KEY'] = '365818fd398f1bc6db5743907791d6c067e9c8362a8d742d74c6e1c811f2abbf'
# 判断系统类型
WIN = sys.platform.startswith('win')
if WIN: # 如果是 Windows 系统,使用三个斜线
prefix = 'sqlite:///'
else: # 否则使用四个斜线
prefix = 'sqlite:'
# sqlite:///数据库文件的绝对地址,如果你使用 Windows 系统只需要写入三个斜线(即 sqlite:///)
app.config['SQLALCHEMY_DATABASE_URI'] = prefix + os.path.join(app.root_path, 'data.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # 关闭对模型修改的监控
db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
user_type = db.Column(db.String(255))
username = db.Column(db.String(255))
password_hash = db.Column(db.String(128)) # 密码散列值
def set_password(self, password): # 用来设置密码的方法,接受密码作为参数
self.password_hash = generate_password_hash(password) # 将生成的密码保持到对应字段
def validate_password(self, password): # 用于验证密码的方法,接受密码作为参数
return check_password_hash(self.password_hash, password) # 返回布尔值
# 使用 click.option() 装饰器设置的两个选项分别用来接受输入用户名和密码。执行 flask admin 命令,输入用户名和密码后,即可创建管理员账户。
@app.cli.command()
@click.option('--username', prompt=True, help='The username used to login.')
@click.option('--password', prompt=True, hide_input=True, confirmation_prompt=True, help='The password used to login.')
def admin(username, password):
"""Create user."""
# 判断数据库是否存在
if sqlalchemy_utils.functions.database_exists(prefix + os.path.join(app.root_path, 'data.db')):
print('Database already exists.')
else:
print('Create database.')
db.create_all()
if db.session.query(User.id).filter_by(username=username).scalar() is not None:
user = User.query.filter_by(username=username).first()
click.echo('Updating user...')
user.set_password(password) # 设置密码
else:
click.echo('Creating user...')
user = User(username=username, user_type='Admin')
user.set_password(password) # 设置密码
db.session.add(user)
db.session.commit() # 提交数据库会话
click.echo('Done.')
@login_manager.user_loader
def load_user(user_id): # 创建用户加载回调函数,接受用户 ID 作为参数
user = User.query.get(int(user_id)) # 用 ID 作为 User 模型的主键查询对应的用户
return user # 返回用户对象
@app.route('/', methods=['GET', 'POST'])
@login_required
def index():
if request.method == "GET":
return render_template('index.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if not username or not password:
flash('Invalid input.')
return redirect(url_for('login'))
user = User.query.filter_by(username=username).first()
# 验证用户名和密码是否一致
if username == user.username and user.validate_password(password):
login_user(user) # 登入用户
# flash('Login success.')
return redirect(url_for('index')) # 重定向到主页
flash('Invalid username or password.') # 如果验证失败,显示错误消息
return redirect(url_for('login')) # 重定向回登录页面
return render_template('login.html')
@app.route('/logout')
@login_required # 用于视图保护,后面会详细介绍
def logout():
logout_user() # 登出用户
flash('Goodbye.')
return redirect(url_for('login')) # 重定向回首页
if __name__ == '__main__':
app.run()
html、css、js 文件下载
百度网盘:链接:https://pan.baidu.com/s/1CfEvY1xjbcn9pKAkwDRIsQ 提取码:3d4q
阿里云盘:https://www.aliyundrive.com/s/GDksRTRvR5x
参考文章:
https://tutorial.helloflask.com/
https://flask-login.readthedocs.io/en/latest/
https://sqlalchemy-utils.readthedocs.io/en/latest/