Python Flask Web框架快速入门

Flask 入门Demo

Flask 开发环境搭建,执行如下指令:

pip install flask
# 第一节: Flask 快速入门from flask import Flask
app = Flask(__name__)@app.route('/flask')
def hello_flask():return 'Hello Flask'app.run()

核心代码剖析:

从 flask 包导入 Flask 类,通过实例化这个类,创建一个程序对象 app。

app = Flask(__name__)

注册一个处理函数,这个函数是处理某个请求的处理函数,Flask 官方把它叫做视图函数(view funciton)。使用 app.route() 装饰器来为这个函数绑定对应的 URL,当用户在浏览器访问这个 URL 的时候,就会触发这个函数,获取返回值,并把返回值显示到浏览器窗口:

@app.route('/flask')
def hello_flask():return 'Hello Flask'

最后,Flask类的run()方法在本地开发服务器上运行应用程序。

app.run(host, port, debug, options)

所有参数都是可选的

序号参数与描述
1

host

要监听的主机名。 默认为127.0.0.1(localhost)。设置为“0.0.0.0”以使服务器在外部可用

2

port

默认值为5000

3

debug

默认为false。 如果设置为true,则提供调试信息

4

options

要转发到底层的Werkzeug服务器。

Flask 基础知识

Flask 入参类型

flask 支持入参数据类型,如下所示:

转换器描述
int整型
float浮点型
path接受用作目录分隔符的斜杠
string默认,字符串
# 第二节: Flask 入参
from flask import Flask, redirectapp = Flask(__name__)# 字符串入参
@app.route('/strs/<name>')
def strs(name):return "Hello %s" % name# 浮点数入参
@app.route('/floats/<float:version>')
def floats(version):return version# 整数入参
@app.route('/ints/<int:version>')
def ints(version):return '整数为 %d' % versionapp.run(host='0.0.0.0', port=8888, debug=True)

Flask 重定向(redirect)

url_for()函数用于动态指定函数的URL地址。

# 第三节: Flask 重定向from flask import Flask, redirect, url_forapp = Flask(__name__)@app.route('/redicts')
def redicts():return redirect('https://www.baidu.com')@app.route('/admin')
def get_admin():return 'Hello Admin'@app.route('/guest/<guest>')
def get_guest(guest):return 'Hello %s as Guest' % guest@app.route('/user/<name>')
def hello_user(name):if name == 'admin':return redirect(url_for('get_admin'))else:return redirect(url_for('get_guest', guest=name))app.run()

Flask 支持到HTTP方法

默认情况下,Flask路由响应GET请求。但是,可以通过为route()装饰器提供方法参数来更改此首选项。

序号方法与描述
1

GET

以未加密的形式将数据发送到服务器。最常见的方法。

2

HEAD

和GET方法相同,但没有响应体。

3

POST

用于将HTML表单数据发送到服务器。POST方法接收的数据不由服务器缓存。

4

PUT

用上传的内容替换目标资源的所有当前表示。

5

DELETE

删除由URL给出的目标资源的所有当前表示。

# 第四节: Flask 支持HTTP方法from flask import Flaskapp = Flask(__name__)@app.route('/get_request', methods=['GET'])
def get_request():return 'GET请求'@app.route('/post_request', methods=['POST'])
def post_request():return 'POST请求'@app.route('/delete_request', methods=['DELETE'])
def delete_request():return 'DELETE请求'@app.route('/put_request', methods=['PUT'])
def put_request():return 'PUT请求'@app.route('/head_request', methods=['HEAD'])
def head_request():return 'HEAD请求'app.run()

 Flask 实战一:模拟用户登入

# Flask 模拟用户登入from flask import Flask, request, jsonifyapp = Flask(__name__)@app.route('/')
def index():return '欢迎来到主页'@app.route('/login', methods=['POST'])
def login():my_json = request.get_json()user = my_json.get('user')password = my_json.get('password')if user == 'admin' and password == '123456':# 前端和后端统一请求和返回的数据格式,返回json格式需要导入jsonify这个包# return jsonify({#     "token": "abcd123456",#     "birthday": "2024-04-18"# })return jsonify(token="abcd123456", birthdat="2024-04-18")app.run()

Flask 模板

在项目下创建 templates 文件夹,用于存放所有模板文件,并在目录下创建一个模板文件: login.html 文件

<html><body><form action = "http://localhost:5000/login" method = "post"><p>用户名:</p><p><input type = "text" name = "user" /></p><p>密码:</p><p><input type = "password" name = "password" /></p><p><input type = "submit" value = "submit" /></p></form></body>
</html>
# Flask 模拟用户登入 : 基于Templatefrom flask import Flask, request, jsonify, render_templateapp = Flask(__name__)@app.route('/')
def index():return render_template("login.html")@app.route('/login', methods=['POST'])
def login():# 由json 获取修改为表单获取user = request.form['user']password = request.form['password']if user == 'admin' and password == '123456':# 前端和后端统一请求和返回的数据格式,返回json格式需要导入jsonify这个包# return jsonify({#     "token": "abcd123456",#     "birthday": "2024-04-18"# })return jsonify(token="abcd123456", birthdat="2024-04-18")app.run()

Flask 模板文件传参

在Python代码中传入字符串,列表,字典到模板中。

from flask import Flask, render_templateapp = Flask(__name__)@app.route('/')
def index():# 字符串my_str = 'Hello Word'# int 类型my_int = 10# 数组类型my_array = [3, 4, 2, 1, 7, 9]# 字典类型my_dict = {'name': 'zhouzhiwengang','age': 31}return render_template('variable.html',my_str=my_str,my_int=my_int,my_array=my_array,my_dict=my_dict)app.run()

Flask 模板文件之静态文件

# 第六节: Flask 模板文件之静态文件
from flask import Flask, render_templateapp = Flask(__name__)@app.route("/")
def index():return render_template("static.html")app.run(debug=True)

在项目下创建 templates 文件夹,用于存放所有模板文件,并在目录下创建一个模板文件: static.html 文件

<html><head><script type = "text/javascript"src = "{{ url_for('static', filename = 'static.js') }}" ></script></head><body><input type = "button" onclick = "sayHello()" value = "Say Hello" /></body></html>

在项目下创建 static文件夹,用于存放javascript文件或支持网页显示的CSS文件,并在目录下创建一个js文件: static.js文件

function sayHello() {alert("Python 模板文件之静态资源文件")
}

Flask Request对象

Request对象的重要属性如下所列:

  • Form - 它是一个字典对象,包含表单参数及其值的键和值对。

  • args - 解析查询字符串的内容,它是问号(?)之后的URL的一部分。

  • Cookies  - 保存Cookie名称和值的字典对象。

  • files - 与上传文件有关的数据。

  • method - 当前请求方法。

# 第七节: Flask Request 对象
# Request对象的重要属性如下所列:
# Form - 它是一个字典对象,包含表单参数及其值的键和值对。
# args - 解析查询字符串的内容,它是问号(?)之后的URL的一部分。
# Cookies  - 保存Cookie名称和值的字典对象。
# files - 与上传文件有关的数据。
# method - 当前请求方法。from flask import Flask, render_template, requestapp = Flask(__name__)@app.route('/')
def student():return render_template('student.html')@app.route('/result', methods=['POST', 'GET'])
def result():if request.method == 'POST':result = request.formreturn render_template("result.html", result=result)app.run(debug=True)

在项目下创建 templates 文件夹,用于存放所有模板文件,并在目录下创建一个模板文件: student.html /result.html文件

student.html

<html><body><form action="http://localhost:5000/result" method="POST"><p>姓名 <input type = "text" name = "Name" /></p><p>物理 <input type = "text" name = "Physics" /></p><p>化学 <input type = "text" name = "chemistry" /></p><p>数学 <input type ="text" name = "Mathematics" /></p><p><input type = "submit" value = "提交" /></p></form></body>
</html>

result.html 

<html><body><table border = 1>{% for key, value in result.items() %}<tr><th> {{ key }} </th><td> {{ value }}</td></tr>{% endfor %}
</table></body>
</html>

Flask Cookie

Cookie以文本文件的形式存储在客户端的计算机上。其目的是记住和跟踪与客户使用相关的数据,以获得更好的访问者体验和网站统计信息。

Cookie 核心方法

设置cookie

默认有效期是临时cookie,浏览器关闭就失效,可以通过 max_age 设置有效期, 单位是秒

 res = make_response('set success')res.set_cookie('username', 'zhouzhiwengang', max_age=3600)

获取cookie

通过request.cookies的方式, 返回的是一个字典。

cookie = request.cookies.get('username')

删除cookie

 res = make_response('del success')res.delete_cookie('username')
# 第七节: Flask Cookie 对象
from flask import Flask, make_response, request  # 注意需导入 make_responseapp = Flask(__name__)@app.route('/set_cookie')
def set_cookie():res = make_response('set success')res.set_cookie('username', 'zhouzhiwengang', max_age=3600)return res@app.route('/get_cookie')
def get_cookie():cookie = request.cookies.get('username')return cookie@app.route('/del_cookie')
def del_cookie():res = make_response('del success')res.delete_cookie('username')return resapp.run()

Flask Session

与Cookie不同,Session(会话)数据存储在服务器上。会话是客户端登录到服务器并注销服务器的时间间隔。需要在该会话中保存的数据会存储在服务器上的临时目录中。

为每个客户端的会话分配会话ID。会话数据存储在cookie的顶部,服务器以加密方式对其进行签名。对于此加密,Flask应用程序需要一个定义的SECRET_KEY

Session对象也是一个字典对象,包含会话变量和关联值的键值对。

Session核心方法

设置密钥

app.secret_key = 'abcd12345678'

设置Session会话变量

session['username'] = request.form['username']

删除Session 会话变量

 session.pop('username', None)
# 第八节: Flask Session 对象from flask import Flask, session, redirect, url_for, escape, requestapp = Flask(__name__)app.secret_key = 'abcd12345678'@app.route('/')
def index():if 'username' in session:# session 会话获取值username = session['username']return '登录用户名是:' + username + '<br>' + \"<b><a href = '/logout'>点击这里注销</a></b>"return "您暂未登录, <br><a href = '/login'></b>" + \"点击这里登录</b></a>"@app.route('/login', methods=['GET', 'POST'])
def login():if request.method == 'POST':user = request.form['username']password = request.form['password']if user == 'admin' and password == '123456':# session 会话设值session['username'] = request.form['username']return redirect(url_for('index'))return '''<form action = "" method = "post"><p>用户名:</p><p><input type = "text" name = "username" /></p><p>密码:</p><p><input type = "password" name = "password" /></p><p><input type = "submit" value = "submit" /></p><p><input type="submit" value ="登录"/></p></form>'''@app.route('/logout')
def logout():# session 会话移除值session.pop('username', None)return redirect(url_for('index'))if __name__ == '__main__':app.run(debug=True)

Flask 错误代码

Flask类具有带有错误代码的abort()函数。

Flask.abort(code)

Code 参数采用以下值之一:

  • 400 - 用于错误请求

  • 401 - 用于未身份验证的

  • 403 - Forbidden

  • 404 - 未找到

  • 406 - 表示不接受

  • 415 - 用于不支持的媒体类型

  • 429 - 请求过多

# 第九节: Flask 错误from flask import Flask, session, redirect, url_for, escape, request, abortapp = Flask(__name__)app.secret_key = 'abcd12345678'@app.route('/')
def index():if 'username' in session:# session 会话获取值username = session['username']return '登录用户名是:' + username + '<br>' + \"<b><a href = '/logout'>点击这里注销</a></b>"return "您暂未登录, <br><a href = '/login'></b>" + \"点击这里登录</b></a>"@app.route('/login', methods=['GET', 'POST'])
def login():if request.method == 'POST':user = request.form['username']password = request.form['password']if user == 'admin' and password == '123456':# session 会话设值session['username'] = request.form['username']return redirect(url_for('index'))else:# 用户验证不通过abort(401)return '''<form action = "" method = "post"><p>用户名:</p><p><input type = "text" name = "username" /></p><p>密码:</p><p><input type = "password" name = "password" /></p><p><input type = "submit" value = "submit" /></p><p><input type="submit" value ="登录"/></p></form>'''@app.route('/logout')
def logout():# session 会话移除值session.pop('username', None)return redirect(url_for('index'))if __name__ == '__main__':app.run(debug=True)

Flask 消息反馈

Flask 模块包含 flash() 方法。它将后端处理消息传递给前端。

# 第十节: Flask 消息反馈from flask import Flask, redirect, url_for, request, render_template, flashapp = Flask(__name__)
# seesion 会话存储临时目录地址
app.secret_key = 'abcde'@app.route('/')
def index():return render_template('response.html')@app.route('/login', methods=['GET', 'POST'])
def login():error = Noneif request.method == 'POST':user = request.form['user']password = request.form['password']if user == 'admin' and password == '123456':flash('登入成功')return redirect(url_for('index'))else:# 用户验证不通过,反馈相关信息error = '非法用户名或密码,请重新登入'return render_template('login.html', error=error)if __name__ == '__main__':app.run(debug=True)

在项目下创建 templates 文件夹,用于存放所有模板文件,并在目录下创建一个模板文件: login.html /response.html文件

login.html

<html><body><form action = "http://localhost:5000/login" method = "post"><p>用户名:</p><p><input type = "text" name = "user" /></p><p>密码:</p><p><input type = "password" name = "password" /></p><p><input type = "submit" value = "submit" /></p></form>{% if error %}<p><strong>错误信息</strong>: {{ error }}</p>{% endif %}</body>
</html>

response.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Flask 消息反馈</title>
</head>
<body>{% with messages = get_flashed_messages() %}{% if messages %}{% for message in messages %}<p>{{ message }}</p>{% endfor %}{% endif %}{% endwith %}
<h3>Welcome!</h3>
<a href = "{{ url_for('login') }}">登入</a>
</body>
</html>

Flask 文件上传

在 Flask 中处理文件上传非常简单。它需要一个 HTML 表单,其 ​enctype​ 属性设置为“​multipart/form-data​,将文件发布到 URL。

URL 处理程序从 ​request.files[] 对象中提取文件,并将其保存到所需的位置。

每个上传的文件首先会保存在服务器上的临时位置,然后将其实际保存到它的最终位置。

目标文件的名称可以是硬编码的,也可以从request.files[file] ​对象的​ filename ​属性中获取。但是,建议使用secure_filename()​ 函数获取它的安全版本。

可以在 Flask 对象的配置设置中定义默认上传文件夹的路径和上传文件的最大大小。

app.config['UPLOAD_FOLDER'] 定义上传文件夹的路径 app.config['MAX_CONTENT_LENGTH'] 指定要上传的文件的最大大小(以字节为单位)
# 第十一节: Flask 文件上传from flask import Flask, render_template, request
from werkzeug.utils import secure_filenameimport osapp = Flask(__name__)
UPLOAD_FOLDER = 'upload'
if not os.path.exists(UPLOAD_FOLDER):os.makedirs(UPLOAD_FOLDER)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER@app.route('/upload')
def upload_file():return render_template('upload.html')@app.route('/uploader', methods=['GET', 'POST'])
def uploader():if request.method == 'POST':f = request.files['file']print(request.files)f.save(os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(f.filename)))return '文件上传成功'else:return render_template('upload.html')if __name__ == '__main__':app.run(debug=True)

Flask 拓展

Flask常用扩展包:

Flask-SQLalchemy:操作数据库;

Flask-script:插入脚本;

Flask-migrate:管理迁移数据库;

Flask-Session:Session存储方式指定;

Flask-WTF:表单;

Flask-Mail:邮件;

Flask-Bable:提供国际化和本地化支持,翻译;

Flask-Login:认证用户状态;

Flask-OpenID:认证;

Flask-RESTful:开发REST API的工具;

Flask-Bootstrap:集成前端Twitter Bootstrap框架;

Flask-Moment:本地化日期和时间;

Flask-Admin:简单而可扩展的管理接口的框架

Flask 拓展之Flask-SQLalchemy

SQLAlchemy是一个关系型数据库框架,它提供了高层的ORM和底层的原生数据库的操作。flask-sqlalchemy是一个简化了SQLAlchemy操作的flask扩展。

安装flask-sqlalchemy扩展, 执行如下指令:
pip install -U Flask-SQLAlchemypip install flask-mysqldbpip install pymysql
SQLAlchemy支持字段类型
类型名python中类型说明
Integerint普通整数,一般是32位
SmallIntegerint取值范围小的整数,一般是16位
BigIntegerint或long不限制精度的整数
Floatfloat浮点数
Numericdecimal.Decimal普通整数,一般是32位
Stringstr变长字符串
Textstr变长字符串,对较长或不限长度的字符串做了优化
Unicodeunicode变长Unicode字符串
UnicodeTextunicode变长Unicode字符串,对较长或不限长度的字符串做了优化
Booleanbool布尔值
Datedatetime.date时间
Timedatetime.datetime日期和时间
LargeBinarystr二进制文件
SQLAlchemy列选项
选项名说明
primary_key如果为True,代表表的主键
unique如果为True,代表这列不允许出现重复的值
index如果为True,为这列创建索引,提高查询效率
nullable如果为True,允许有空值,如果为False,不允许有空值
default为这列定义默认值
SQLAlchemy关系选项
选项名说明
backref在关系的另一模型中添加反向引用
primary join明确指定两个模型之间使用的联结条件
uselist如果为False,不使用列表,而使用标量值
order_by指定关系中记录的排序方式
secondary指定多对多中记录的排序方式
secondary join在SQLAlchemy中无法自行决定时,指定多对多关系中的二级联结条件
Flask-SQLalchemy 实战之快速入门
# 第十一节: Flask 拓展之数据库(flask-sqlalchemy), 快速入门
# 导入Flask及相关扩展库
from flask import Flask
from flask_sqlalchemy import SQLAlchemy# 创建Flask应用实例
app = Flask(__name__)# 配置MySQL数据库连接
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:123456@192.168.43.10/house'
db = SQLAlchemy(app)# 定义ORM模型,表示数据库表
class Table(db.Model):__tablename__ = 'base_house'id = db.Column(db.String(255), primary_key=True)# 路由函数,查询库下所有表名,并返回
@app.route('/')
def get_tables():tables = Table.query.all()house_list = []for user in tables:user_data = {'id': user.id}house_list.append(user_data)return {'users': house_list}if __name__ == '__main__':app.run()
Flask-SQLalchemy 实战之分页查询和参数筛选
# 第十一节: Flask 拓展之数据库(flask-sqlalchemy), 分页 + 入参查询
# 导入Flask及相关扩展库
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy# 创建Flask应用实例
app = Flask(__name__)# 配置MySQL数据库连接
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:123456@192.168.43.10/house'
db = SQLAlchemy(app)# 定义ORM模型,表示数据库表
class Table(db.Model):__tablename__ = 'base_house'id = db.Column(db.String(255), primary_key=True)project_no = db.Column(db.String(255))project_name = db.Column(db.String(255))project_address = db.Column(db.String(255))# 路由函数,查询库下所有表名,并返回
@app.route('/', methods=['POST'])
def get_tables():parame_json = request.get_json()page = parame_json.get('page')size = parame_json.get('size')name = parame_json.get('name')if name:houses = Table.query.filter_by(project_name=name).paginate(page=page, per_page=size, error_out=False)else:houses = Table.query.paginate(page=page, per_page=size, error_out=False)house_list = []for house in houses:house_data = {'id': house.id,'projectNo': house.project_no,'projectName': house.project_name,'projectAddress': house.project_address}house_list.append(house_data)return jsonify({'users': house_list,'total_pages': houses.pages,'current_page': houses.page})if __name__ == '__main__':app.run()

涉及base_house 表DDL:

CREATE TABLE `base_house` (`id` varchar(64) NOT NULL,`project_no` varchar(128) DEFAULT NULL,`project_name` varchar(256) DEFAULT NULL,`project_address` varchar(256) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Flask 拓展之Flask-Login

扩展 Flask-Login 提供了实现用户认证需要的各类功能函数,我们将使用它来实现程序的用户认证,首先来安装它:

pip install flask-login

app.py:初始化 Flask-Login

from flask_login import LoginManagerlogin_manager = LoginManager(app)  # 实例化扩展类@login_manager.user_loader
def load_user(user_id):  # 创建用户加载回调函数,接受用户 ID 作为参数user = User.query.get(int(user_id))  # 用 ID 作为 User 模型的主键查询对应的用户return user  # 返回用户对象

Table模型类继承 Flask-Login 提供的 UserMixin 类:

# 定义ORM模型,表示数据库表
class Table(UserMixin, db.Model):__tablename__ = 't_admin'id = db.Column(db.Integer, primary_key=True)username = db.Column(db.String(30))userpwd = db.Column(db.String(100))

 

# 第十二节: Flask 拓展之数据库(flask-sqlalchemy)/认证框架(flask-login), 使用用户登入并方法鉴权
from flask import Flask, request, jsonify, redirect, url_for, render_template
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user# 创建Flask应用实例
app = Flask(__name__)
# seesion 会话存储临时目录地址
app.secret_key = 'abcde1234'# 配置MySQL数据库连接
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:123456@192.168.43.10/house'
db = SQLAlchemy(app)# 初始化登录管理器
login_manager = LoginManager()
login_manager.init_app(app)# 定义ORM模型,表示数据库表
class Table(UserMixin, db.Model):__tablename__ = 't_admin'id = db.Column(db.Integer, primary_key=True)username = db.Column(db.String(30))userpwd = db.Column(db.String(100))# 加载用户的回调函数
@login_manager.user_loader
def load_user(user_id):return Table.query.get(int(user_id))# 定义登录路由
@app.route('/login', methods=['GET', 'POST'])
def login():if request.method == 'POST':username = request.form['username']password = request.form['password']user = Table.query.filter_by(username=username).first()if user and user.userpwd == password:login_user(user)return redirect(url_for('dashboard'))return render_template('auth_login.html')# 定义需要鉴权的页面
@app.route('/dashboard')
@login_required
def dashboard():return render_template('dashboard.html')# 定义登出路由
@app.route('/logout')
@login_required
def logout():logout_user()return redirect(url_for('login'))if __name__ == '__main__':app.run()

Flask 拓展之Flask-JWT-Extended

JWT简介

具体原理请参考:JSON Web Token 入门教程

JWT结构

JWT由三部分组成:

  • 头部(Header):通常包含令牌的类型(JWT)和使用的加密算法。
  • 载荷(Payload):包含有关用户或其他数据的信息。例如,用户ID、角色或其他自定义数据。
  • 签名(Signature):由头部、载荷和密钥组合而成的签名,用于验证令牌的完整性和来源可信度。

JWT生成和校验

  1. 用户登录时,服务器使用密钥签署JWT,并将其返回给客户端。
  2. 客户端在以后的请求中发送JWT作为身份验证令牌。
  3. 服务器验证JWT的签名以确保其完整性,然后使用载荷中的信息进行用户身份验证和授权。

Flask-JWT-Extended 

Flask-JWT-Extended是一个Python库,用于在 Flask 应用程序中添加JSON Web令牌(JWT)支持。它是一个插件,可以通过安装它来扩展Flask应用程序的功能。

官网地址:Flask-JWT_Extended 官网

Flask-JWT-Extended 安装

pip install Flask-JWT-Extended

实战:Flask-SQLalchemy + MySQL 8  + Flask-JWT-Extended 实现前后端分离用户认证和鉴权。

# _*_ coding : UTF-8_*_
# 开发者 : zhuozhiwengang
# 开发时间 : 2024/4/19 9:26
# 文件名称 : 19
# 开发工具 : PyCharm
# 第十二节: Flask 拓展之数据库(flask-sqlalchemy)/认证框架(flask-jwt-extend), 实现用户前后端分离认证和鉴权
from flask import Flask, request, jsonify, redirect, url_for, render_template, abort
from flask_sqlalchemy import SQLAlchemy
from flask_jwt_extended import (JWTManager, jwt_required, create_access_token, get_jwt_identity)# 创建Flask应用实例
app = Flask(__name__)
# 用于签名JWT的密钥
app.config['JWT_SECRET_KEY'] = 'abc123'# 配置MySQL数据库连接
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:123456@192.168.43.10/house'
db = SQLAlchemy(app)# 初始化JWT扩展
jwt = JWTManager(app)# 定义ORM模型,表示数据库表
class Table(db.Model):__tablename__ = 't_admin'id = db.Column(db.Integer, primary_key=True)username = db.Column(db.String(30))userpwd = db.Column(db.String(100))# 定义登录路由
@app.route('/login', methods=['GET', 'POST'])
def login():if request.method == 'POST':username = request.form['username']password = request.form['password']user = Table.query.filter_by(username=username).first()if user and user.userpwd == password:access_token = create_access_token(identity=username)return jsonify(access_token=access_token)else:# 用户名或密码错误abort(401)# 定义需要鉴权的页面
@app.route('/dashboard')
@jwt_required()  # 这个装饰器要求请求必须携带有效的JWT令牌
def dashboard():# 使用get_jwt_identity访问当前用户的身份current_user = get_jwt_identity()return jsonify(logged_in_as=current_user)if __name__ == '__main__':app.run()

第一种情况:输入错误用户名或密码,提示401错误代码

控制台输出信息:

WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.* Running on http://127.0.0.1:5000
Press CTRL+C to quit
127.0.0.1 - - [19/Apr/2024 09:36:45] "POST /login HTTP/1.1" 401 -

 第二种情况:输入正确用户名和密码,获取凭证Token

 第三种情况:拼接头信息,访问受保护资源

Flask-JWT-Extended 核心代码讲解 

初始化

from flask import Flask
from flask_jwt_extended import (JWTManager, jwt_required, create_access_token, get_jwt_identity)app = Flask(__name__)
# 用于签名JWT的密钥
app.config['JWT_SECRET_KEY'] = 'your-secret-key' # 初始化JWT扩展
jwt = JWTManager(app)

生成和校验

  • 定义了 /login 路由,用于用户登录并获取JWT令牌。在这个路由中,首先从请求中获取用户名和密码(这里是 “zzg” 和 “123456”)。如果匹配成功,就使用 create_access_token 函数生成JWT令牌,并返回给客户端。
  • 定义了 /protected 路由,它是受保护的路由,只有在请求中包含有效的JWT令牌时才能访问。这是通过 @jwt_required() 装饰器实现的。
    • 如果请求中没有有效的JWT令牌,访问该路由会返回未授权的响应。
    • 如果令牌有效,路由会使用 get_jwt_identity() 函数获取JWT中的身份信息(在示例中为用户名)然后返回一个JSON响应,显示已登录的用户

 Flask-JWT-Extended 优化:设置Token有效期、刷新Token

设置Token有效期

设置JWT的过期时间是一种重要的安全措施,可以帮助确保令牌不会无限期有效,提高了应用程序的安全性。

方法一:

使用 app.config['JWT_ACCESS_TOKEN_EXPIRES'] 来设置JWT的访问token默认过期时间为1小时。

# 设置ACCESS_TOKEN的默认过期时间为1小时
app.config['JWT_ACCESS_TOKEN_EXPIRES'] = timedelta(hours=1)

方法二:

当使用create_access_token函数创建JWT令牌时,也可以通过传递expires_delta参数来覆盖默认的过期时间,例如:

  • 这将覆盖默认的过期时间,使得令牌在30分钟后过期。
from datetime import timedelta
# 设置ACCESS_TOKEN的默认过期时间为30分钟
access_token = create_access_token(identity=username, expires_delta=timedelta(minutes=30))

刷新Token 

认证Token与刷新Token差异

访问tokenAccess Token刷新tokenRefresh Token
用途用于访问受保护的资源用于获取新的访问token
生命周期默认为15分钟默认为30天
显式指定生命周期JWT_ACCESS_TOKEN_EXPIRESJWT_REFRESH_TOKEN_EXPIRES
储存方式在请求的头信息(Header)中的 “Authorization” 字段中一般存储在服务器端的数据库

每个用户生成的刷新token访问token是一一对应的,

当用户登录成功后,服务器会为该用户生成一对刷新token访问token,并将它们关联到用户的身份(通常是用户的用户名或ID)。这样,每个用户都有自己唯一的刷新token访问token

刷新token用于获取新的访问token,以延长用户的会话时间。只有拥有有效的刷新token的用户才能获取新的访问token,而访问token则用于实际访问受保护的资源。

实战:Flask-SQLalchemy + MySQL 8  + Flask-JWT-Extended 实现前后端分离用户认证和鉴权。添加刷新Token和使用刷新Token鉴权。

# 第十二节: Flask 拓展之数据库(flask-sqlalchemy)/认证框架(flask-jwt-extend), 实现用户前后端分离认证和鉴权
from flask import Flask, request, jsonify, redirect, url_for, render_template, abort
from flask_sqlalchemy import SQLAlchemy
from flask_jwt_extended import (JWTManager, jwt_required, create_access_token, get_jwt_identity, create_refresh_token)# 创建Flask应用实例
app = Flask(__name__)
# 用于签名JWT的密钥
app.config['JWT_SECRET_KEY'] = 'abc123'# 配置MySQL数据库连接
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:123456@192.168.43.10/house'
db = SQLAlchemy(app)# 初始化JWT扩展
jwt = JWTManager(app)# 定义ORM模型,表示数据库表
class Table(db.Model):__tablename__ = 't_admin'id = db.Column(db.Integer, primary_key=True)username = db.Column(db.String(30))userpwd = db.Column(db.String(100))# 定义登录路由
@app.route('/login', methods=['GET', 'POST'])
def login():if request.method == 'POST':username = request.form['username']password = request.form['password']user = Table.query.filter_by(username=username).first()if user and user.userpwd == password:access_token = create_access_token(identity=username)refresh_token = create_refresh_token(identity=username)return jsonify(access_token=access_token, refresh_token=refresh_token)else:# 用户名或密码错误abort(401)# 使用刷新token获取新的访问token
@app.route("/refresh", methods=["POST"])
@jwt_required(refresh=True)  # 使用刷新token进行验证
def refresh():current_user = get_jwt_identity()access_token = create_access_token(identity=current_user)return jsonify(access_token=access_token)# 定义需要鉴权的页面
@app.route('/dashboard')
@jwt_required()  # 这个装饰器要求请求必须携带有效的JWT令牌
def dashboard():# 使用get_jwt_identity访问当前用户的身份current_user = get_jwt_identity()return jsonify(logged_in_as=current_user)if __name__ == '__main__':app.run()

相关截图:

Flask 拓展之flask_restful 

flask_restful安装

pip install flask_restful

实战:Flask-SQLalchemy + MySQL 8 +Flask_Restful 实现Restful 接口

from flask import Flask, request, jsonify
from flask_restful import Api, Resource
from flask_sqlalchemy import SQLAlchemy# 创建Flask应用实例
app = Flask(__name__)# 配置MySQL数据库连接
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:123456@192.168.43.10/house'
db = SQLAlchemy(app)
api = Api(app)# 定义ORM模型,表示数据库表
class Table(db.Model):__tablename__ = 'base_house'id = db.Column(db.String(255), primary_key=True)project_no = db.Column(db.String(255))project_name = db.Column(db.String(255))project_address = db.Column(db.String(255))class UserAPI(Resource):def get(self, user_id):user = Table.query.get(user_id)if user:return {'id': user.id, 'projectNo': user.project_no, 'projectName': user.project_name, 'projectAddress': user.project_address}else:return {'message': 'House not found'}, 404def post(self):data = request.get_json()new_user = Table(project_no=data['projectNo'], project_name=data['projectName'], project_address=data['projectAddress'], id=data['id'])db.session.add(new_user)db.session.commit()return {'message': '创建成功'}, 201def delete(self, user_id):user = Table.query.get(user_id)if user:db.session.delete(user)db.session.commit()return {'message': '删除成功'}else:return {'message': '记录未找到'}, 404api.add_resource(UserAPI, '/user', '/user/<user_id>')if __name__ == '__main__':app.run(port=8081)

Flask 高级

待补充Flask高级内容主要涉及:Python 多线程、Python连接Redis、Python连接MongoDB、Python 连接Elasticsearch、Python MinoIO 文件服务器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/826984.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RTSP/Onvif视频监控平台EasyNVR如何提高匿名用户的用户名和密码安全性?

EasyNVR安防视频云平台是旭帆科技TSINGSEE青犀旗下支持RTSP/Onvif协议接入的安防监控流媒体视频云平台。平台具备视频实时监控直播、云端录像、云存储、录像检索与回看、告警等视频能力&#xff0c;能对接入的视频流进行处理与多端分发&#xff0c;包括RTSP、RTMP、HTTP-FLV、W…

Nginx+Lua+OpenResty(详解及使用)

一、 Nginx简介 Nginx是一个高性能的Web服务器和反向代理的软件。 Web服务器&#xff1a;就是运行我们web服务的容器&#xff0c;提供web功能&#xff0c;还有tomcat也提供类似的功能。 代理是软件架构和网络设计中&#xff0c;非常重要的一个概念。 二、Nginx的反向代理&…

flutter 谷歌的苹果系统消息推送

flutter firebase 云消息通知教程 (android-安卓、ios-苹果) Android、ReactNative、Flutter集成Firebase推送注意事项 Android&#xff1a;Firebase 凭据 iOS&#xff1a;基于 p8 令牌的 APN 连接 iOS&#xff1a;p12 生成证书 Flutter之对接国外推送onesignal踩坑笔记&a…

0.C++入门(专栏前言)

目录 1.什么是C 2.C的发展史 3.C的重要性 应用&#xff1a; 4.如何学习C 5.关于本专栏 1.什么是C 20世纪80年代&#xff0c;计算机界提出oop(object oriented programming:面向对象&#xff09;思想&#xff0c;支持面向对象的程序设计应运而生。 1982年&#xff0c;本…

Java实现文件分片上传、大文件秒传

Java实现文件分片上传、大文件秒传&#xff0c;大文件如何做断点续传&#xff1f;JAVAWEB 文件上传及下载&#xff0c;JAVA大文件上传&#xff0c;大文件下载解决方案&#xff0c;JAVA实现文件分片上传并且断点续传&#xff0c;JAVA大文件分片上传/多线程上传功能&#xff0c;超…

JS-47-Node.js06-fs模块-读写文件

Node.js内置的fs模块就是文件系统模块&#xff0c;负责读写文件。 和所有其它JavaScript模块不同的是&#xff0c;fs模块同时提供了异步和同步的方法。 一、回顾&#xff1a;异步方法VS同步方法 1-1、异步方法 因为JavaScript的单线程模型&#xff0c;执行IO操作时&#xff…

STP学习的第一篇

1.STP的基本概念&#xff1a;根桥 &#xff08;1&#xff09;STP的主要作用之一是在整个交换网络中计算出一棵无环的“树”&#xff08;STP树&#xff09;。 &#xff08;2&#xff09;根桥是一个STP交换网络中的“树根”。 &#xff08;3&#xff09;STP开始工作后&#xf…

【C++类和对象】初始化列表与隐式类型转换

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

《C语言深度解剖》(8):一篇文章彻底学会Visual Studio 调试技巧,新手必看!

&#x1f921;博客主页&#xff1a;醉竺 &#x1f970;本文专栏&#xff1a;《C语言深度解剖》 &#x1f63b;欢迎关注&#xff1a;感谢大家的点赞评论关注&#xff0c;祝您学有所成&#xff01; ✨✨&#x1f49c;&#x1f49b;想要学习更多数据结构与算法点击专栏链接查看&am…

MySQL 基础语法(2)

文章目录 创建表查看表修改表表数据插入 本文为表结构相关的基础语言库相关的基础语句 创建表 CREATE TABLE table_name ( field1 datatype comment xxx, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引擎;CREATE TABLE&#xff1…

NLP(2)--搭建简单的模型(nn)

前言 仅记录学习过程&#xff0c;有问题欢迎讨论 可能使用到的包 可以通过Anaconda直接install&#xff0c;不行就PIP install xxx PythonTorchTransformersScikit-learnNumpyGensimPandas 我的版本&#xff1a; 可以用 conda list 查看 代码 如果有包导入不进来&…

如何搭建私域获取淘宝店铺卖家订单信息trade.fullinfo.get

私域流量主要由已经对企业或品牌感兴趣并进行关注的用户组成&#xff0c;这些用户对企业具有一定的忠诚度和粘性。通过与这些用户建立良好的互动和关系&#xff0c;企业可以进一步提升用户的忠诚度和转化率&#xff0c;从而有助于建立持续稳定的业务模式和盈利模式&#xff0c;…

【ARFoundation自学01】搭建AR框架+检测平面+点击克隆立方体到地面=自信入门!

介绍 AR 的功能其实是个大手机系统厂商和眼镜设备厂商开发的功能&#xff0c;并不是Unity的功能&#xff0c;毕竟Unity没有自己的手机设备&#xff01;比如谷歌公司的安卓开发了ARcore&#xff0c;让所有安卓8.0版本以上的用户能够在手机上体验AR功能&#xff01;苹果推出了AR…

2024红明谷杯——Misc 加密的流量

2024红明谷杯——Misc 加密的流量 写在前面&#xff1a; 这里是贝塔贝塔&#xff0c;照例来一段闲聊 打比赛但赛前一波三折&#xff0c;又是成功签到的一个比赛 说起来比赛全名叫红明谷卫星应用数据安全场景赛&#xff0c;但好像真的跟卫星的关系不大&#xff0c;没有bin方…

深入探索Python中的推导式:从列表到字典,全面解析数据结构的快速构建方法

文章目录 1. 列表推导式&#xff1a;快速构造列表1.1 基础用法1.2 条件筛选 2. 字典推导式&#xff1a;动态构建字典2.1 基础用法2.2 使用条件过滤 3. 集合推导式&#xff1a;有效去重与数据筛选3.1 基本语法与应用3.2 去重和转换3.2 使用条件过滤 4. 生成器推导式&#xff1a;…

基于CH32V103的多功能推杆设计

一、项目简介 “创意源于生活&#xff0c;工具始于懒惰。” 整体造型外观参考了最近比较火的夫妻游戏《双人成行》第一关里面那个吸尘器的推杆开关&#xff0c;结构中采用阻尼器/滚珠轴承等器件&#xff0c;使其非常具有质感和手感。功能上我构思不能只有电脑开关这么简单地一…

Jenkins CI/CD 持续集成专题三 Jenkins 使用shell脚本打包组件配置流程

第一步 新建任务 第二步 输入项目名称和选择自由风格的软件项目点击确定 第三步 配置下项目地址和账号密码 第四步 配置 build steps 选择 shell 脚本 第五步 shell 配置 &#xff08;注意shell 必须以#!/bin/sh开头&#xff0c;否则会报 找不到shell 命令的错&#xff09; …

【Web】DASCTF X CBCTF 2022九月挑战赛 题解

目录 dino3d Text Reverser cbshop zzz_again dino3d 进来是一个js小游戏 先随便玩一下&#xff0c;显示要玩够1000000分 直接console改分数会被检测 先是JSFinder扫一下&#xff0c;扫出了check.php 到js里关键词索引搜索check.php 搜索sn&#xff0c;发现传入的参数是…

3-羟基丙酸(3-HP)应用前景广阔 生物基3-羟基丙酸市场占比将不断提升

3-羟基丙酸&#xff08;3-HP&#xff09;应用前景广阔 生物基3-羟基丙酸市场占比将不断提升 合成技术是制约3-羟基丙酸规模化应用的重要因素。3-羟基丙酸合成技术包括化学合成法、生物合成法两大类&#xff0c;其中化学合成法是主流生产工艺&#xff0c;但化学合成法存在工艺复…

.netcore+vue新生分班系统的设计与实现

.netcore vue新生分班系统的设计与实现说明文档 运行前附加数据库.mdf&#xff08;或sql生成数据库&#xff09; 主要技术&#xff1a; 基于.net core架构和mysql数据库vue 东北石油大学新生分班系统的设计与实现 功能模块&#xff1a; 登录 注册学生 忘记密码 系统首顶 个…