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, redirect

app = 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' % version


app.run(host='0.0.0.0', port=8888, debug=True)

Flask 重定向(redirect)

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

# 第三节: Flask 重定向

from flask import Flask, redirect, url_for

app = 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 Flask

app = 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, jsonify

app = 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 模拟用户登入 : 基于Template

from flask import Flask, request, jsonify, render_template

app = 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_template

app = 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_template

app = 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, request

app = 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.form
        return 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_response

app = 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 res


app.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, request

app = 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, abort

app = 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, flash

app = 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 = None
    if 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_filename

import os

app = 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-SQLAlchemy

pip install flask-mysqldb

pip 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 LoginManager

login_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'}, 404

    def 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': '创建成功'}, 201

    def delete(self, user_id):
        user = Table.query.get(user_id)
        if user:
            db.session.delete(user)
            db.session.commit()
            return {'message': '删除成功'}
        else:
            return {'message': '记录未找到'}, 404


api.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 文件服务器。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【机器学习】小波变换在特征提取中的实践与应用

小波变换在特征提取中的实践与应用 一、小波变换的基本原理与数学表达二、基于小波变换的特征提取方法与实例三、小波变换在特征提取中的优势与展望 在信号处理与数据分析领域&#xff0c;小波变换作为一种强大的数学工具&#xff0c;其多尺度分析特性使得它在特征提取中扮演着…

2024最新面试跳槽,软件测试面试题的整理与解析

今天接着来说说测试工程师面试比较高频的面试题&#xff0c;大家可以通过面试题内的一些解析再结合自己的真实工作经验来进行答题思路的提取、整理。 硬背答案虽可&#xff0c;但容易翻车哦。能够举一反三才是重点&#xff01; 1&#xff1a;请介绍一下UI自动化测试中三种时间等…

解线性方程组——上三角、下三角,回代算法 | 北太天元

解上三角(回代) a i i ≠ 0 a_{ii\neq0} aii0​ , i 1 , 2 , … , n i1,2,\ldots,n i1,2,…,n a 11 x 1 a 12 x 2 ⋯ a 1 n x n b 1 a 22 x 2 ⋯ a 2 n x n b 2 ⋯ a n n x n b n \begin{aligned} a_{11}x_1a_{12}x_2\cdotsa_{1n}x_n&b_1 \\ a_{22}x_2\cdotsa_…

从零开始搭建社交圈子系统:充实人脉的最佳路径

线上交友圈&#xff1a;拓展社交网络的新时代 线上交友圈是社交网络的新引擎&#xff0c;提供了更广泛的社交机会&#xff0c;注重共同兴趣的连接&#xff0c;强调多样性的社交形式&#xff0c;更真实地展示自己&#xff0c;让朋友更全面地了解我们的生活状态。虽然虚拟交往存在…

【智能算法】饥饿游戏搜索算法(HGS)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2021年&#xff0c;Yang等人受到自然界饥饿驱动的活动和动物的行为选择启发&#xff0c;提出了饥饿游戏搜索算法&#xff08;Hunger Games Search, HGS&#xff09;。 2.算法原理 2.1算法思想 HGS…

SPN的相关利用(下)

Kerberoasting kerberos通信过程&#xff1a; 在TGS-REQ中会发出ST服务票据获取servicePrincipalName(SPN)&#xff0c;该SPN是用户或者机器用户注册的。TGS-REP中TGS会返回给user一个ST&#xff0c;而ST是由user请求的server的密码进行加密的&#xff0c;我们可以从TGS-REP中…

RT-Thread时钟管理

操作系统需要通过时间来规范其任务,主要介绍时钟节拍和基于时钟节拍的定时器。 时钟节拍 任何操作系统都需要提供一个时钟节拍,以供系统处理所有和时间有关的事件,如线程的延时、线程的时间片轮转调度以及定时器超时等。 RT-Thread 中,时钟节拍的长度可以根据 RT_TICK_P…

Module外贸主题开心版下载-v5.7.0版本WordPress企业模板

主题下载地址&#xff1a;Module外贸主题开心版下载-v5.7.0版本 Module主题介绍&#xff1a;采用全新模块化开发&#xff0c;首页模块可视化拖拽自由组合&#xff0c;可自定义搭建出不同行业适用的企业网站。同时主题全面支持WPML多语言切换&#xff0c;可轻松搭建外贸网站。W…

JetBrains Rider 2024.1.1 .NET集成开发环境 mac/win

JetBrains Rider是一个新的跨平台的基于Inte lliJ平台和ReSharper的. NET集成技术开发工作环境。 Rider提供了大量人工智能系统代码进行编辑管理功能&#xff0c;如不同类型的代码可以完成、自动设备名称发展空间设计导入、自动通过插入大括号和突出研究显示信息匹配作为分隔符…

torchEEG工具箱

文章信息: 题目&#xff1a;TorchEEGEMO&#xff1a;基于脑电图的情绪识别深度学习工具箱 期刊&#xff1a;Expert Systems with Applications 环境&#xff1a;pytorch 1.11.0 CUDA 11.3 摘要&#xff1a; ​ 一个python工具箱TorchEEG&#xff0c;将工作流程分为五个模块…

软考 - 系统架构设计师 - 架构风格例题

问题一&#xff1a; 什么是软件架构风格&#xff1f; 软件架构风格指特定软件系统组织方式的惯用模式。组织方式描述了系统的组成构件和这些构件的组织方式。惯用模式反映了众多系统所共有的结构和语义。 集成开发环境与用户的交互方式 &#xff08;实际上询问在交互方面&am…

干货-PMP常考知识点,都给你们汇总到这里了

PMP认证考试考来考去&#xff0c;其实就是那些知识点。把这些知识点吃透了&#xff0c;你会发现做题稳准狠。不仅速度快&#xff0c;正确率也有很大的提升。 我们结合了10几年PMP备考辅导经验&#xff0c;给大家梳理了这些PMP常考的知识点集锦&#xff0c;希望能帮到大家&#…

css中all 的使用记录

all 在 CSS 中是一个特殊的属性值&#xff0c;它允许我们重置元素或元素父级的所有属性到其初始值、继承的值或取消设置的值。这一属性非常有用&#xff0c;特别是在需要快速重置多个属性的情况下&#xff0c;它避免了逐一设置每个属性的繁琐过程。 先看一下浏览器兼容性&#…

【SAP HANA 15】SQL锁表 (查询,解锁)

锁表查看 --锁表检查语句 SELECT C.CONNECTION_ID,PS.STATEMENT_STRINGFROM M_CONNECTIONS C JOIN M_PREPARED_STATEMENTS PSON C.CONNECTION_ID PS.CONNECTION_ID AND C.CURRENT_STATEMENT_ID PS.STATEMENT_IDWHERE C.CONNECTION_STATUS RUNNINGAND C.CONNECTION_TYPE Re…

第二届数据安全大赛暨首届“数信杯”数据安全大赛数据安全积分争夺赛-东区预赛部分WP

这里写目录标题 检材下载&#xff1a;1.理论题2.数据安全&#xff1a;pb:Sepack&#xff1a; 3.数据分析&#xff1a;数据分析&#xff08;1&#xff09;数据分析1-1:数据分析1-2:数据分析1-3: 数据分析&#xff08;3&#xff09;数据分析3-1&#xff1a;数据分析3-2&#xff1…

2024年04月18日优雅草便民tools开源-git以及dcloud同步-长期更新

优雅草小工具-数据来自优雅草api赋能 优雅草小工具-数据来自优雅草api赋能-优雅草便民工具是一款由成都市一颗优雅草科技有限公司打造的便民查询公益工具&#xff0c;2024年1月17日正式发布v1.0.0版本&#xff0c;本工具为了方便大众免费使用&#xff0c;本生活小工具会陆续加入…

Oracle——领先的企业级数据库解决方案

一、WHAT IS ORACLWE&#xff1a; ORACLE 数据库系统是美国 ORACLE 公司&#xff08;甲骨文&#xff09;提供的以分布式数据库为核心的一组软件产品&#xff0c;是目前最流行的客户/服务器(CLIENT/SERVER)或B/S 体系结构的数据库之一&#xff0c;ORACLE 通常应用于大型系统的数…

C#基于SSE传递消息给Vue前端实现即时单向通讯

一、简述 通常前端调用后端的API&#xff0c;调用到了&#xff0c;等待执行完&#xff0c;拿到返回的数据&#xff0c;进行渲染&#xff0c;流程就完事了。如果想要即时怎么办&#xff1f;如果你想问什么场景非要即时通讯&#xff0c;那可就很多了&#xff0c;比如在线聊天、实…

gpt能生成ppt吗

gpt能生成ppt吗 GPT是一个高度通用的工具&#xff0c;适用于多种场景和领域&#xff0c;制作ppt只是它强大功能的冰山一角&#xff0c;具体包括&#xff1a; 信息查询与解释&#xff1a; 提供科学、技术、历史、文化等领域的详细解释和背景信息。 解答疑问&#xff0c;帮助…

前端css中transition的使用

前端css中transition的使用 一、前言二、transition的4个属性三、例子1.源码12.源码1运行效果 四、结语五、定位日期 一、前言 CSS中的transition&#xff08;过渡&#xff09;&#xff0c;根据字面意思就可以理解成一种变化状态的过程。当我们有一个方形&#xff0c;我们想让…