Python Flask Web框架快速入门

news2024/11/19 18:40:54

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

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

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

相关文章

微信小程序开发之多图片上传+.NET WebAPI后端服务保存图片资源

前言&#xff1a; 最近开发的一个微信小程序项目需要做一个同时选中三张&#xff08;或者是多张&#xff09;图片一起上传到服务端&#xff0c;服务端保存图片资源并保存的功能。发现在微信小程序开发中会有很多场景会使用到多图片上传并保存到的功能&#xff0c;所以我把自己总…

酷开科技抓住“客厅经济”发展的机遇,不断对酷开系统升级赋能

酷开科技抓住“客厅经济”发展的机遇&#xff0c;不断对酷开系统升级赋能&#xff0c;打造新的生活场景&#xff0c;满足消费者的不同生活需求&#xff0c;酷开科技的产品和服务让消费者能够在家庭空间中享受到更加智能、便捷和温馨的时光。同样凭借更加包容、开放的生态体验&a…

unordered_map 与map使用说明

目录 背景&#xff1a; 问题分析&#xff1a; 使用APE工具&#xff0c;查看录制的原始门信号是否存在异常 查看报文读取是否存在问题 分析报文读取代码 为什么在Windows系统中&#xff0c;解析后的门信号没有存在跳变情况 是否Windows 和Linux下 unordered_map中数据先后…

文本批量高效编辑管理,支持将文本进行自定义行数进行拆分,实现文本的高效管理

在信息爆炸的时代&#xff0c;文本文件的管理和编辑成为了许多工作和学习中不可或缺的一部分。面对大量的文本内容&#xff0c;如何高效地进行编辑和管理成为了一个挑战。现在&#xff0c;我们为您带来了一款强大的批量文本编辑管理工具&#xff0c;支持自定义行数拆分&#xf…

面试题集中营—分布式共识算法

分布式共识算法目标 分布式主要就是为了解决单点故障。一开始只有一个服务节点提供服务&#xff0c;如下图所示。那么如果服务节点挂了&#xff0c;对不起等着吧。 为了服务的高可用性&#xff0c;我们一般都会多引入几个副节点当备份&#xff0c;当服务节点挂了&#xff0c;就…

BRC20铭文铭刻解析

BRC20铭文铭刻的出现对于智能制造无疑是一个重要的里程碑。随着科技的飞速发展&#xff0c;智能制造已经成为制造业发展的必然趋势&#xff01;智能制造是指通过运用人工智能、物联网、大数据等先进技术&#xff0c;实现生产过程的自动化、智能化和高效化。 1. BRC20铭文的概念…

2024常见的自动化测试工具和框架!

在软件测试领域&#xff0c;自动化测试框架有很多&#xff0c;这里主要介绍几种常用的自动化测试框架。 以下是几种常用的自动化测试框架&#xff1a; Selenium&#xff1a;Selenium 是一个功能强大的Web应用程序测试框架&#xff0c;支持多种编程语言&#xff0c;如Java、Pyt…

在ELF 1开发环境中使用Qt Creator进行远程调试

Qt Creator是一款跨平台集成开发环境&#xff08;IDE&#xff09;&#xff0c;主要适用于支持Qt框架的各类应用程序开发。其内置的远程调试机制使得开发者能够在本地开发环境中对部署在远程设备上的代码进行调试&#xff0c;无需直接对远程设备进行操作。Qt Creator会通过网络连…

Django中的实时通信:WebSockets与异步视图的结合

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 在现代Web应用程序中&#xff0c;实时通信已经成为了必不可少的功能之一。无论是在线聊天、…

将图片按灰度转换成字符

from struct import *ch [., :, !, ~, ,, ^, *,$, #]//可以在这里面由浅到深添加字符 ch.reverse()def calc(R, G, B):#模式Lreturn R * 299 // 1000 G * 587 // 1000 B * 144 / 1000def character( val):num val / 260 * len(ch)num round(num)if num>len(ch):numlen(…

【H4012】3.3V5V12V24V30V,3.5A大电流温度低 高效同步降压芯片IC DC-DC

您提到的“3.3V, 5V, 12V, 24V, 30V, 3.5A 高效同步降压芯片IC DC-DC”是指一种能够将较高电压&#xff08;例如24V或30V&#xff09;降至较低电压&#xff08;例如3.3V, 5V或12V&#xff09;的直流-直流&#xff08;DC-DC&#xff09;转换器。这种转换器通常使用同步降压技术&…

uniapp 安卓批量异步权限授权,没有授权就跳系统App设置页

首先需要一个js的sdk&#xff1a;App权限判断和提示 - DCloud 插件市场 下载下来&#xff0c;引入里面的 permission.js 示例代码&#xff1a; <script>import { requestAndroidPermission } from ./sdk/permission.jsexport default {onLaunch(e) {const getMutiPer…

kerberos:适配华为FI

文章目录 一、hive1、hive thrift连接方式 一、hive 1、hive thrift连接方式 kerberos认证失败信息 缺少配置&#xff1a;{“hadoop.rpc.protection”:“privacy”}&#xff0c;具体可参考&#xff1a;kerbros认证相关问题 华为FI参考资料&#xff1a; https://github.com…

从零开始学习Linux(4)----yum和vim

1.Linux软件包管理器yum Linux中我们要进行工具/指令/程序&#xff0c;安装&#xff0c;检查卸载等&#xff0c;需要yum的软件 安装软件的方式&#xff1a; 源代码安装---交叉编译的工具rpm包直接安装yum/apt-get yum是我们Linux预装的一个指令&#xff0c;搜索&#xff0c;下…

如何防止用户手动填写身份证信息来作弊?

当前有不少的网站或企业需要用户采用身份证读卡器远程在程序里面填写身份证信息&#xff0c;用于核实用户的真实身份&#xff0c;以完成某些业务&#xff0c;但是&#xff0c;有些用户为了达到不可告人的目的&#xff0c;会采用作弊手段&#xff0c;绕过机器采集这一关&#xf…

牛客网:环形链表的约瑟夫问题

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;每日一练 &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f3dd;1.问题描述&#xff1a; 前言&#xff1a; 约瑟夫问题 有很多种解决办法&#xff0c;下面我们用链表进行解题 题目链…

学校管网的仿写

工字形布局完成 效果 代码部分 在这里插入代码片 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport…

AI日报:最强大模型Llama 3发布;Midjourney推社交新功能Room;超强AI视频自动剪辑工具Captions;手机上可以玩大模型了

新鲜AI产品点击了解&#xff1a;https://top.aibase.com/ 1、最强大模型Llama3 正式发布 已达GPT4 级别 Llama3是Meta公司最新发布的开源模型&#xff0c;拥有80亿和700亿参数规模&#xff0c;预计7月正式发布。该模型具备多模态能力&#xff0c;集成了新的计算机编码功能&am…

C++类和对象(中)(2)

一、拷贝构造函数 1.1 拷贝构造函数的概念 在现实生活中我们对于两个一模一样的人我们将他们称之为双胞胎&#xff0c;那么我们在创建对象的时候&#xff0c;能不能创建一个和已经存在的对象一模一样的新对象呢&#xff1f;这种做法是可以的&#xff0c;通过拷贝构造函数我们…

Docker镜像的使用与操作

1、什么是镜像 Docker镜像是用于创建容器的只读模板&#xff0c;它包含文件系统。一个Docker镜像可以包括一个应用程序以及能够运行它的基本操作系统环境。 镜像是创建容器的基础&#xff0c;通过版本管理和联合文件系统&#xff0c;Docker提供了一套十分简单的机制来创建镜像…