Flask中的JWT认证构建安全的用户身份验证系统

👽发现宝藏

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。

Flask中的JWT认证:构建安全的用户身份验证系统

随着Web应用程序的发展,用户身份验证和授权变得至关重要。JSON Web Token(JWT)是一种流行的身份验证方法,它允许在网络应用程序之间安全地传输信息。在Python领域中,Flask是一种流行的Web框架,它提供了许多工具来简化JWT身份验证的实现。

在本文中,我们将探讨如何使用Flask和JWT构建一个安全的用户身份验证系统。我们将介绍JWT的工作原理,然后演示如何在Flask应用程序中集成JWT来实现用户身份验证。

什么是JWT?

JWT是一种基于JSON的开放标准(RFC 7519),用于在网络应用程序之间传输信息。它由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。这三部分通过点号连接在一起,形成了一个JWT令牌,例如:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

  • 头部(Header):包含了JWT的类型(例如,JWT)和使用的加密算法(例如,HMAC SHA256或RSA)。
  • 载荷(Payload):包含了声明,例如用户ID和角色。它也可以包含其他自定义的声明。
  • 签名(Signature):用于验证JWT的完整性,以确保未被篡改。

使用Flask和JWT实现用户身份验证

首先,我们需要安装所需的库。我们可以使用pip来安装FlaskPyJWT

pip install Flask PyJWT

接下来,我们创建一个简单的Flask应用程序,实现JWT身份验证。我们将使用JWT来生成和验证令牌,并使用Flask的路由来实现登录和受保护的资源访问。

from flask import Flask, request, jsonify
import jwt
from functools import wraps

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'  # 设置用于签名JWT的密钥

# 模拟用户数据库
users = {
    'username': 'password'
}

# 身份验证装饰器
def token_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        token = request.args.get('token')

        if not token:
            return jsonify({'message': 'Token is missing!'}), 403

        try:
            data = jwt.decode(token, app.config['SECRET_KEY'])
        except:
            return jsonify({'message': 'Token is invalid!'}), 403

        return f(*args, **kwargs)

    return decorated

# 登录路由
@app.route('/login')
def login():
    auth = request.authorization

    if auth and auth.username in users and users[auth.username] == auth.password:
        token = jwt.encode({'username': auth.username}, app.config['SECRET_KEY'])
        return jsonify({'token': token.decode('UTF-8')})

    return jsonify({'message': 'Authentication failed!'}), 401

# 受保护的路由
@app.route('/protected')
@token_required
def protected():
    return jsonify({'message': 'Protected resource!'})

if __name__ == '__main__':
    app.run()

在上面的示例中,我们首先导入所需的库,并设置了用于签名JWT的密钥。然后,我们模拟了一个简单的用户数据库,并创建了一个装饰器token_required,用于验证JWT令牌。接着,我们定义了两个路由:/login用于登录并生成JWT令牌,/protected是一个受保护的资源,需要提供有效的JWT令牌才能访问。

进一步示例代码

用户管理

在用户管理方面,我们可以扩展我们的示例代码以支持用户注册、管理和密码重置。下面是一个简单的示例:

# 用户数据库
users = {
    'username': {'password': 'hashed_password', 'email': 'user@example.com'}
}

# 注册路由
@app.route('/register', methods=['POST'])
def register():
    data = request.get_json()
    username = data.get('username')
    password = data.get('password')
    email = data.get('email')

    if username in users:
        return jsonify({'message': 'Username already exists!'}), 400

    # 在实际应用中,密码应该进行哈希处理,以增加安全性
    users[username] = {'password': password, 'email': email}
    return jsonify({'message': 'User registered successfully!'}), 201
令牌刷新

为了实现令牌刷新机制,我们可以添加一个额外的路由来接受令牌并返回新的令牌。下面是一个简单的示例:

# 令牌刷新路由
@app.route('/refresh_token', methods=['POST'])
@token_required
def refresh_token():
    token = request.args.get('token')

    try:
        data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'], options={'verify_exp': False})
        new_token = jwt.encode({'username': data['username']}, app.config['SECRET_KEY'])
        return jsonify({'token': new_token.decode('UTF-8')})
    except:
        return jsonify({'message': 'Token is invalid!'}), 403

在这个示例中,我们使用了一个额外的路由/refresh_token来接受一个旧的JWT令牌,并使用相同的用户信息生成一个新的令牌。需要注意的是,我们关闭了过期验证选项,以便在旧令牌过期后生成新令牌。

通过实现这些功能,我们可以进一步增强我们的用户身份验证系统,并提供更好的用户体验和安全性。这些示例代码可以作为起点,帮助您构建出更完整和功能强大的应用程序。

日志和监控

在实际应用中,添加日志记录和监控功能对于跟踪和分析用户活动以及识别潜在的安全问题至关重要。下面是一个简单的示例,演示如何使用Flask内置的日志记录功能来记录请求信息:

import logging

# 设置日志记录级别
logging.basicConfig(level=logging.INFO)

# 登录路由
@app.route('/login')
def login():
    auth = request.authorization

    logging.info(f"Login attempt with username: {auth.username}")

    if auth and auth.username in users and users[auth.username] == auth.password:
        token = jwt.encode({'username': auth.username}, app.config['SECRET_KEY'])
        logging.info(f"Login successful for username: {auth.username}")
        return jsonify({'token': token.decode('UTF-8')})

    logging.info(f"Login failed for username: {auth.username}")
    return jsonify({'message': 'Authentication failed!'}), 401

通过添加日志记录,我们可以在服务器端记录每次登录尝试的详细信息,以便后续分析和监控。

安全性增强

为了增强安全性,我们可以采取一些额外的措施来保护用户身份验证过程中的敏感信息。下面是一些建议:

  • 使用HTTPS:通过使用HTTPS来加密通信,可以防止中间人攻击和窃听,从而保护用户的凭据和数据。
  • 限制登录尝试次数:实施登录尝试次数限制和锁定账户机制,以防止暴力破解密码。
  • 密码哈希存储:对用户密码进行哈希处理,并采用适当的哈希算法和盐值来增加密码的安全性。

完整示例代码

下面是经过改进和扩展的完整示例代码,包括用户管理、令牌刷新、日志记录和安全性增强:

from flask import Flask, request, jsonify
import jwt
import logging
from functools import wraps

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'

# 模拟用户数据库
users = {
    'username': {'password': 'hashed_password', 'email': 'user@example.com'}
}

# 设置日志记录级别
logging.basicConfig(level=logging.INFO)

# 身份验证装饰器
def token_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        token = request.args.get('token')

        if not token:
            return jsonify({'message': 'Token is missing!'}), 403

        try:
            data = jwt.decode(token, app.config['SECRET_KEY'])
        except:
            return jsonify({'message': 'Token is invalid!'}), 403

        return f(*args, **kwargs)

    return decorated

# 注册路由
@app.route('/register', methods=['POST'])
def register():
    data = request.get_json()
    username = data.get('username')
    password = data.get('password')
    email = data.get('email')

    if username in users:
        return jsonify({'message': 'Username already exists!'}), 400

    # 在实际应用中,密码应该进行哈希处理,以增加安全性
    users[username] = {'password': password, 'email': email}
    return jsonify({'message': 'User registered successfully!'}), 201

# 登录路由
@app.route('/login')
def login():
    auth = request.authorization

    logging.info(f"Login attempt with username: {auth.username}")

    if auth and auth.username in users and users[auth.username]['password'] == auth.password:
        token = jwt.encode({'username': auth.username}, app.config['SECRET_KEY'])
        logging.info(f"Login successful for username: {auth.username}")
        return jsonify({'token': token.decode('UTF-8')})

    logging.info(f"Login failed for username: {auth.username}")
    return jsonify({'message': 'Authentication failed!'}), 401

# 令牌刷新路由
@app.route('/refresh_token', methods=['POST'])
@token_required
def refresh_token():
    token = request.args.get('token')

    try:
        data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'], options={'verify_exp': False})
        new_token = jwt.encode({'username': data['username']}, app.config['SECRET_KEY'])
        return jsonify({'token': new_token.decode('UTF-8')})
    except:
        return jsonify({'message': 'Token is invalid!'}), 403

# 受保护的路由
@app.route('/protected')
@token_required
def protected():
    return jsonify({'message': 'Protected resource!'})

if __name__ == '__main__':
    app.run()

通过结合用户管理、令牌刷新、日志记录和安全性增强,我们可以构建一个更加完善和安全的用户身份验证系统。这个示例提供了一个起点,您可以根据实际需求进一步定制和扩展。

HTTPS支持

在实际部署中,为了增强安全性,我们应该使用HTTPS来加密通信,防止中间人攻击和窃听。下面是如何在Flask应用程序中启用HTTPS支持的示例代码:

from flask import Flask, request, jsonify
import jwt
import logging
from functools import wraps
from OpenSSL import SSL

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'

# 模拟用户数据库
users = {
    'username': {'password': 'hashed_password', 'email': 'user@example.com'}
}

# 设置日志记录级别
logging.basicConfig(level=logging.INFO)

# 身份验证装饰器
def token_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        token = request.args.get('token')

        if not token:
            return jsonify({'message': 'Token is missing!'}), 403

        try:
            data = jwt.decode(token, app.config['SECRET_KEY'])
        except:
            return jsonify({'message': 'Token is invalid!'}), 403

        return f(*args, **kwargs)

    return decorated

# 注册路由、登录路由、令牌刷新路由和受保护的路由保持不变

if __name__ == '__main__':
    context = ('cert.pem', 'key.pem')  # 指定证书和密钥文件
    app.run(host='0.0.0.0', port=443, ssl_context=context)

在这个示例中,我们使用了OpenSSL库来生成证书和密钥文件。您需要提前准备好这两个文件,然后将其传递给ssl_context参数以启用HTTPS支持。这样一来,您的Flask应用程序将在443端口上运行,并使用HTTPS加密通信。

安全性评估

在部署和更新您的应用程序之前,确保进行安全性评估和审查,以识别并修复潜在的安全问题。进行安全性测试、漏洞扫描和代码审查是保护您的应用程序免受攻击的关键步骤。

JWT的优势

使用JWT进行身份验证具有许多优势:

  1. 无状态性(Stateless):JWT令牌包含了所有必要的信息,因此服务器不需要在自己的存储中保存会话状态。这使得JWT非常适合于构建无状态的API,减轻了服务器的负担,并使得应用程序更易于扩展。

  2. 跨域支持(Cross-Origin Support):由于JWT令牌可以在HTTP请求头或URL参数中传输,因此非常适合用于跨域请求。这使得在不同域之间进行身份验证变得更加简单。

  3. 可扩展性(Scalability):JWT是基于JSON的标准,因此可以包含任意数量的声明。这使得JWT非常灵活,可以轻松地扩展以满足不同的需求。

  4. 安全性(Security):JWT令牌可以使用密钥进行签名,以确保其完整性。这使得服务器能够验证令牌是否被篡改,从而确保用户身份的安全性。

进一步发展

虽然上面的示例提供了一个基本的JWT身份验证实现,但在实际应用中可能需要进一步的发展和改进。一些可能的改进包括:

  • 用户管理:实现用户注册、管理和密码重置等功能,以及更复杂的用户权限管理。
  • 令牌刷新:实现令牌刷新机制,以允许用户在令牌过期前获取新的令牌。
  • 日志和监控:添加日志记录和监控功能,以便跟踪和分析用户活动和身份验证请求。
  • 安全性增强:考虑使用HTTPS和其他安全措施来保护身份验证流程中的敏感信息。

通过不断改进和完善身份验证系统,可以提高应用程序的安全性和可用性,并为用户提供更好的体验。

总结

在本文中,我们深入探讨了如何使用Flask和JWT构建安全的用户身份验证系统。我们首先介绍了JWT的工作原理和优势,然后提供了一个完整的示例代码,展示了如何在Flask应用程序中实现用户注册、登录、令牌刷新和受保护路由等功能。

通过结合用户管理、令牌刷新、日志记录和安全性增强,我们建立了一个更加完善和安全的用户身份验证系统。我们还介绍了如何使用HTTPS来加密通信,以增强应用程序的安全性。

最后,我们强调了进行安全性评估和审查的重要性,并鼓励开发者不断学习和改进,以保持应用程序与最新的安全最佳实践保持一致。Flask和JWT为构建安全、可靠的Web应用程序提供了一个强大的基础,我们可以利用它们来保护用户的凭据和数据,为用户提供更好的服务和保护。

在这里插入图片描述

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

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

相关文章

Linux给磁盘扩容(LVM方式)

Linux给磁盘扩容(LVM方式) 最近测试性能,在本地打数据时,发现磁盘空间不足,于是想手动给/挂载点添加空间。这里介绍通过LVM方式快速给磁盘扩容。 LVM:是一种技术,方便管理磁盘。如果不用LVM,那…

js的算法-交换排序(快速排序)

快速排序 基本思想 快速排序的基本思想是基于分治法的:在待排序表L【1...n】中任意取一个元素p 作为枢轴(或基准,通常取首元素)。通过一趟排序将待排序表划分为独立的两部分L【1...k-1】和L【k1...n】;这样的话,L【1…

Linux下的基本指令

基本指令 前言ls 指令语法功能常用选项举例注意关于拼接关于 -a关于文件ls与/的联用ls与根目录ls与任意文件夹ls与常用选项与路径 pwd命令语法功能常用选项注意window与Linux文件路径的区别 cd 指令语法功能举例注意cd路径... touch指令语法功能常用选项 mkdir指令语法功能常用…

【RAG 论文】Query2doc — 使用 LLM 做 Query Expansion 来提高信息检索能力

论文:Query2doc: Query Expansion with Large Language Models ⭐⭐⭐⭐⭐ Microsoft Research, EMNLP 2023 文章目录 背景介绍Query2doc 论文速读实现细节实验结果和分析总结分析 背景介绍 信息检索(Information Retrieval,IR)指…

如何操作HTTP返回头-ApiHug小技巧-002

🤗 ApiHug {Postman|Swagger|Api...} 快↑ 准√ 省↓ GitHub - apihug/apihug.com: All abou the Apihug apihug.com: 有爱,有温度,有质量,有信任ApiHug - API design Copilot - IntelliJ IDEs Plugin | Marketplace &…

如何用微信小程序实现远程控制无人售货柜

如何用微信小程序实现远程控制无人售货柜呢? 本文描述了使用微信小程序调用HTTP接口,实现控制无人售货柜,独立控制售货柜、格子柜的柜门。 可选用产品:可根据实际场景需求,选择对应的规格 序号设备名称厂商1智能WiFi…

【Canvas与艺术】绘制金色八卦图

【关键点】 等比例缩放各部件及将八卦转为“二进制”的过程。 【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>使用…

gcc make makefile cmake之间的关系梳理

gcc是GNU Compiler Collection&#xff08;GNU编译器套件&#xff09;&#xff0c;也可以简单认为是编译器&#xff0c;它可以编译很多编程语言&#xff08;包括C、C、Object-C、Fortran、Java等&#xff09;当你的程序只有一个源文件&#xff0c;直接用gcc命令编译它。但是当你…

【Java--数据结构】提升你的编程段位:泛型入门指南,一看就会!

前言 泛型是一种编程概念&#xff0c;它允许我们编写可以适用于多种数据类型的代码。通过使用泛型&#xff0c;我们可以在编译时期将具体的数据类型作为参数传递给代码&#xff0c;从而实现代码的复用和灵活性。 在传统的编程中&#xff0c;我们通常需要为不同的数据类型编写不…

总结一下背包里的顺序和是否逆序

1.对于01背包而言&#xff0c;一维压缩态只能物品到背包且需要逆序 2.对应多重背包而言&#xff0c;组合数物品到背包&#xff0c;排列数背包到物品&#xff0c;且都需要正序

【北京迅为】《iTOP-3588开发板系统编程手册》-第20章 socket 应用编程

RK3588是一款低功耗、高性能的处理器&#xff0c;适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用&#xff0c;RK3588支持8K视频编解码&#xff0c;内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP&…

Mudem,打造私密安全、高效稳定的私人空间

Mudem 是 Codigger 平台中的一个关键组件&#xff0c;它提供基础通讯服务&#xff0c;确保不同类型的机器之间可以进行安全和高效的连接。它其设计理念在于将本地机器、公有云以及私有云上的设备无缝地整合为一个可远程在线访问的工作站&#xff08;Workstation&#xff09;。这…

UE4_常见动画节点学习_Two Bone IK双骨骼IK

学习资料&#xff0c;仅供参考&#xff01; Two Bone IK 控制器将逆运动&#xff08;IK&#xff09;解算器应用于到如角色四肢等3关节链。 变量&#xff08; HandIKWeight &#xff09;被用于在角色的 hand_l 和 hand_r 控制器上驱动 关节目标位置&#xff08;Joint Target Lo…

Java常见输入输出练习

1.AB(1) 计算ab 数据范围&#xff1a; 数据组数 1≤ t ≤100 , 数据大小满足 1≤ n ≤1000 输入描述&#xff1a; 输入包括两个正整数a,b(1 < a, b < 1000),输入数据包括多组。 输出描述&#xff1a; 输出ab的结果 输入例子&#xff1a; 1 5 10 20 输出例子&#xff…

ctfshow 每周大挑战RCE极限挑战

讨厌SQl看到这个了想来玩玩 rce1 <?phperror_reporting(0); highlight_file(__FILE__);$code $_POST[code];$code str_replace("(","括号",$code);$code str_replace(".","点",$code);eval($code);?>括号过滤点过滤&…

qt;lt;等xml|Html转义字符

在写Android布局文件时&#xff0c;左右尖括号<>&#xff0c;括号在XML中没办法直接使用&#xff0c;需要进行转义&#xff0c;收集一些转义符&#xff0c;以便查询使用。 常用表&#xff1a; **对于文章出现的任何问题请大家批评指出&#xff0c;一定及时修改 **可联系…

牛客网刷题 | BC60 判断是不是字母

描述 KiKi想判断输入的字符是不是字母&#xff0c;请帮他编程实现。 输入描述&#xff1a; 多组输入&#xff0c;每一行输入一个字符。 输出描述&#xff1a; 针对每组输入&#xff0c;输出单独占一行&#xff0c;判断输入字符是否为字母&#xff0c;输出内容详见输出样例…

加密、解密、签名、验签、数字证书、CA浅析

一、加密和解密 加密和解密应用的很广&#xff0c;主要作用就是防止数据或者明文被泄露。 加解密算法主要有两大类&#xff0c;对称加密和非对称加密。对称加密就是加密和解密的密钥都是一个&#xff0c;典型的有AES算法。非对称加密就是有公钥和私钥&#xff0c;公钥可以发布…

在线测径仪的六类测头组合形式!哪种适合你?

在线测径仪&#xff0c;这一现代工业的精密仪器&#xff0c;犹如一位技艺高超的工匠&#xff0c;以其卓越的性能和精准度&#xff0c;为工业生产提供了坚实的保障。它的出现&#xff0c;不仅提高了生产效率&#xff0c;更保证了产品质量&#xff0c;为企业的可持续发展注入了强…

1张图片+3090显卡微调Qwen-VL视觉语言大模型(仅做演示、效果还需加大数据量)

原项目地址&#xff1a;https://github.com/QwenLM/Qwen-VL/blob/master/README_CN.md 环境本地部署&#xff08;见之前博文&#xff09; 【本地部署 】23.08 阿里Qwen-VL&#xff1a;能对图片理解、定位物体、读取文字的视觉语言模型 (推理最低12G显存) 一、数据集格式说明 …