You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot:如何刷新JWT过期时间以支持长期API调用

解决长期运行脚本调用JWT认证API的过期问题

这个场景我之前处理过不少,长期运行的后台脚本碰到JWT过期确实很头疼,给你几个实用的解决方案,你可以根据自己的业务场景来选:

1. 实现JWT自动刷新机制

这是最通用的方案,核心思路是用Refresh Token来换取新的Access Token,避免每次过期都要手动登录。

  • 首先在你的Spring Boot应用里新增一个刷新令牌的API,比如POST /api/auth/refresh,这个接口接收请求头里的Refresh Token,验证有效后返回新的Access Token(可选返回新的Refresh Token,看你的令牌策略)。
  • 脚本这边要维护两个令牌:当前有效的Access Token和对应的Refresh Token,同时记录Access Token的过期时间。
  • 每次调用目标API前,先检查Access Token是否即将过期(比如提前5分钟,避免网络延迟导致刚好过期):
    • 如果没过期,直接用当前Token请求;
    • 如果快过期了,先调用刷新接口获取新Token,更新本地存储的令牌和过期时间,再发起请求;
    • 如果刷新接口返回失败(比如Refresh Token也过期了),就触发重新登录流程,获取新的Access和Refresh Token。

举个Python脚本的简单示例:

import requests
import time

class APIClient:
    def __init__(self, base_url, username, password):
        self.base_url = base_url
        self.username = username
        self.password = password
        self.access_token = None
        self.refresh_token = None
        self.token_expiry = 0

    def login(self):
        # 调用登录接口获取初始令牌
        resp = requests.post(f"{self.base_url}/api/auth/login", json={
            "username": self.username,
            "password": self.password
        })
        resp.raise_for_status()
        data = resp.json()
        self.access_token = data["accessToken"]
        self.refresh_token = data["refreshToken"]
        self.token_expiry = time.time() + data["expiresIn"]  # expiresIn是令牌有效期(秒)

    def refresh_token_if_needed(self):
        # 提前5分钟触发刷新
        if time.time() >= self.token_expiry - 300:
            resp = requests.post(f"{self.base_url}/api/auth/refresh", headers={
                "Authorization": f"Bearer {self.refresh_token}"
            })
            if resp.status_code == 401:
                # Refresh Token过期,重新执行登录
                self.login()
            else:
                resp.raise_for_status()
                data = resp.json()
                self.access_token = data["accessToken"]
                self.token_expiry = time.time() + data["expiresIn"]

    def call_protected_api(self):
        self.refresh_token_if_needed()
        resp = requests.get(f"{self.base_url}/api/protected/data", headers={
            "Authorization": f"Bearer {self.access_token}"
        })
        resp.raise_for_status()
        return resp.json()

# 使用示例
client = APIClient("http://your-spring-boot-app.com", "service-user", "secure-password")
client.login()
while True:
    # 长期运行的任务逻辑
    data = client.call_protected_api()
    # 存入数据库的逻辑(这里省略具体实现)
    print("数据已存入数据库")
    time.sleep(3600)  # 每小时调用一次API

2. 使用服务专用的长期令牌

如果你的脚本是后台服务使用,不需要关联具体用户,可以创建一个服务账户,给它颁发有效期更长的JWT(比如30天、90天甚至1年)。

  • 在Spring Boot里配置专门的服务认证逻辑,比如允许服务账户用客户端凭证模式(Client Credentials)获取令牌,这种令牌的有效期可以设置得比用户令牌长很多;
  • 注意安全:这个服务账户的权限要遵循最小权限原则,只能访问脚本需要的那个API;令牌要存在安全的地方,比如环境变量、密钥管理工具,绝对不能硬编码在脚本里;
  • 定期轮换令牌:即使有效期长,也要定期手动或自动轮换,降低令牌泄露的风险。

3. 捕获401错误并自动重试

如果不想提前维护过期时间,可以在脚本里捕获401 Unauthorized响应,触发重新登录后重试请求。

  • 脚本每次调用API后检查响应状态码:
    • 如果是401,先执行登录流程获取新Token,然后用新Token重新发起请求;
    • 要注意添加重试次数限制(比如最多重试2次),避免因为其他原因导致的401陷入死循环;
    • 如果是多线程/并发脚本,要加锁,避免多个请求同时触发登录,造成不必要的请求。

示例(Python):

def call_protected_api_with_retry(client):
    max_retries = 2
    for attempt in range(max_retries):
        try:
            resp = requests.get(f"{client.base_url}/api/protected/data", headers={
                "Authorization": f"Bearer {client.access_token}"
            })
            if resp.status_code == 401:
                print("令牌过期,重新登录...")
                client.login()
                continue
            resp.raise_for_status()
            return resp.json()
        except Exception as e:
            if attempt == max_retries - 1:
                print(f"重试{max_retries}次后仍失败:{str(e)}")
                raise e

4. 集成令牌管理工具

如果你的脚本是Java写的,可以直接用Spring Security OAuth2 Client的令牌管理功能,它会自动处理令牌的获取、刷新和过期重试等逻辑;如果是其他语言,也可以找对应的库,比如Python的requests-oauthlib,它支持OAuth2的令牌自动刷新。

比如Java里用Spring OAuth2 Client的话,只需要配置好客户端信息,RestTemplate或WebClient会自动处理令牌状态,你不用手动维护令牌的过期和刷新逻辑。


内容的提问来源于stack exchange,提问作者MrG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:45:20