如何在Flask中优雅的使用装饰器刷新令牌

随着现代应用对安全性和用户体验的不断追求,令牌验证和刷新机制已成为每个开发者必须掌握的技能。在这篇引人入胜的技术文章中,我们将深入探讨如何使用Python装饰器优雅地处理访问令牌的刷新,让您的代码不仅高效而且易于维护。

一、引言

在当今的Web应用中,OAuth 2.0和JWT(JSON Web Tokens)已经成为身份验证和授权的主流技术。然而,这些技术的核心挑战之一是如何在访问令牌过期后无缝地刷新它,同时不中断用户的体验。本文将向您展示如何利用Python的强大装饰器功能,轻松实现这一目标。

二、装饰器基础

装饰器是Python中一种高级的语言特性,它允许我们在不修改原始函数代码的情况下,增加额外的功能或行为。在本例中,我们将创建一个名为with_refresh的装饰器,它将负责检测访问令牌是否过期,并在必要时自动刷新它。

三、实现令牌刷新逻辑

首先,我们需要定义一个refresh_access_token函数,该函数将负责与认证服务器通信以获取新的访问令牌。这个函数的实现可能会因您的具体认证流程而异,但关键是要确保它能正确处理成功和失败的情况。

接下来,我们将创建with_refresh装饰器。这个装饰器将接受一个函数作为参数,并在其内部调用该函数。在调用过程中,装饰器将检查响应的状态码,如果状态码为401(表示未授权,可能是因为令牌过期),则触发令牌刷新逻辑。

为了提高可靠性,我们可以进一步使用retrying库来自动重试刷新令牌的操作。这样,即使在网络延迟或认证服务器暂时不可用的情况下,我们也能最大限度地保证用户体验。

四、集成到实际应用中

最后,我们将展示如何将with_refresh装饰器应用到实际的API调用中。只需在需要自动刷新令牌的方法上添加@with_refresh注解,即可享受装饰器为我们带来的便利。

以下是一个完整的示例:

复制代码
import time
import requests
from retrying import retry

# 定义 API 服务的基本 URL
BASE_URL = 'http://127.0.0.1:5000'
access_token = str()
refresh_token = str()


def login(uname: str, passwd: str):
    login_url = f"{BASE_URL}/login"
    data = {"username": uname, "password": passwd}
    resp = requests.post(login_url, json=data)
    if resp.status_code == 200:
        return resp.json().get("access_token"), resp.json().get("refresh_token")
    else:
        print("Login failed.")
        return None, None


@retry(stop_max_attempt_number=3, wait_fixed=2000)
def refresh_access_token():
    global access_token
    refresh_url = f"{BASE_URL}/refresh"
    headers = {
        "Authorization": f"Bearer {refresh_token}"
    }
    resp = requests.post(refresh_url, headers=headers)
    if resp.status_code == 200:
        access_token = resp.json().get("access_token")
        return True
    else:
        print("Token refresh failed.")
        return None


def with_refresh(func):
    def wrapper(*arg, **kwargs):
        try:
            resp = func(*arg, **kwargs)
            if resp.status_code == 401:
                raise Exception(resp.json().get('msg'))
            else:
                return resp
        except Exception as e:
            print(f"Error: {e}")
            new_access_token = refresh_access_token()
            if new_access_token:
                return func(*arg, **kwargs)
            else:
                print("Token refresh failed.")
                return None
    return wrapper


@with_refresh
def get_protected_data():
    headers = {"Authorization": f"Bearer {access_token}"}
    protected_url = f"{BASE_URL}/data"
    return requests.get(protected_url, headers=headers)


if __name__ == "__main__":
    access_token, refresh_token = login("test", "test")
    response = get_protected_data()
    print(response.json())
    time.sleep(62)
    response = get_protected_data()
    print(response.json())

在这个示例中,我们使用了一个装饰器 with_refresh 来处理访问令牌过期的情况。当访问受保护的数据时,如果访问令牌已过期,我们会尝试使用刷新令牌来刷新访问令牌。如果刷新成功,我们会再次尝试访问受保护的数据。如果刷新失败,我们会返回一个错误消息。

五、结论

通过本文的介绍,您已经学会了如何使用Python装饰器优雅地处理访问令牌的刷新问题。这种方法不仅提高了代码的可读性和可维护性,还确保了即使在令牌过期的情况下,用户也能获得流畅的应用体验。

相关推荐
SamChan909 分钟前
PyMuPDF vs pdfplumber vs pypdf:PDF 文本提取实测对比(翻译预处理视角)
python·ai·pdf
oradh20 分钟前
Oracle联机日志文件损坏故障总结
数据库·oracle·oracle联机日志文件损坏
辰辉创聚30 分钟前
炎症与免疫相关细胞因子:信号通路、分类及科研检测应用
python·oracle·nycodenz·重组il-6蛋白·抗tnf-α抗体·il-1β蛋白
IvorySQL33 分钟前
PostgreSQL 日报|8 字节 TOAST 值支持(9 月 16 日)
数据库·人工智能·postgresql
ai小陈35 分钟前
LTX2.5音视频生成任务验收实战:批量记录与音画质量检查
人工智能·python·深度学习·ai·音视频·gpu算力
今儿敲了吗37 分钟前
04英文文本关键词提取(TF-IDF)
笔记·python
绘梨衣5471 小时前
PDF跨页表格处理方案(极简落地版 + 工具对比)
python·rag
实验室管理云平台1 小时前
北京盛元广通推疾控中心实验室管理系统,提升检测效率
数据库·python
玫幽倩1 小时前
2026第二届湾区杯网络安全大赛决赛(AI专项赛道静态题wp)
pytorch·python·ai·agent·ctf·rag·湾区杯
TechWayfarer1 小时前
IP地址查询之后:如何在请求抵达前识别风险
python·tcp/ip·网络安全