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

Go后端应用Token过期时的刷新及并发控制实现求助

Go后端全局Token自动刷新与并发安全实现方案

核心思路

要实现Token过期自动刷新且避免并发重复刷新,核心是通过并发安全的锁机制控制Token的读写,同时用双重检查逻辑防止多个请求同时触发刷新操作。


1. 封装全局Token与并发控制

首先定义全局的Token管理结构体,使用sync.RWMutex(读多写少场景更高效)保护Token的读写操作:

import (
    "fmt"
    "net/http"
    "sync"
    "time"

    "github.com/gorilla/mux"
)

type Token struct {
    Name         string
    Value        string
    RefreshValue string
    Expires      time.Time
}

// 全局Token实例与读写锁
var (
    appToken   Token
    tokenMutex sync.RWMutex
)

2. 初始化全局Token

在main函数中完成初始Token的获取:

func main() {
    // 初始化全局Token,失败则终止服务
    var err error
    appToken, err = GetToken()
    if err != nil {
        panic("初始化Token失败: " + err.Error())
    }

    router := mux.NewRouter()
    router.HandleFunc("/employees", GetEmployeesHandler).Methods("GET")
    // 启动HTTP服务(示例)
    if err := http.ListenAndServe(":8080", router); err != nil {
        panic("服务启动失败: " + err.Error())
    }
}

// GetToken 初始化获取Token的逻辑(替换为你的实际业务代码)
func GetToken() (Token, error) {
    return Token{
        Name:         "app-token",
        Value:        "initial-valid-token",
        RefreshValue: "initial-refresh-token",
        Expires:      time.Now().Add(24 * time.Hour),
    }, nil
}

3. 实现安全的Token自动刷新逻辑

编写GetValidToken函数,负责Token有效性检查与自动刷新,通过双重检查+锁机制保证并发安全:

// GetValidToken 返回当前有效的Token,若即将过期则自动刷新
func GetValidToken() (Token, error) {
    // 第一步:加读锁快速检查Token状态(不阻塞其他读请求)
    tokenMutex.RLock()
    currentToken := appToken
    tokenMutex.RUnlock()

    // 提前5分钟检查是否即将过期,避免刚好在请求处理中过期
    if time.Now().Add(5 * time.Minute).Before(currentToken.Expires) {
        return currentToken, nil
    }

    // 第二步:Token即将过期,加写锁准备刷新(同一时间仅一个goroutine能进入)
    tokenMutex.Lock()
    defer tokenMutex.Unlock()

    // 双重检查:加锁后再次确认,防止其他goroutine已完成刷新
    if time.Now().Add(5 * time.Minute).Before(appToken.Expires) {
        return appToken, nil
    }

    // 执行刷新操作(替换为你的实际刷新逻辑)
    newToken, err := RefreshToken(appToken.RefreshValue)
    if err != nil {
        return Token{}, err
    }

    // 更新全局Token
    appToken = newToken
    return newToken, nil
}

// RefreshToken 用旧的RefreshValue获取新Token(替换为你的实际业务代码)
func RefreshToken(refreshValue string) (Token, error) {
    // 示例:调用第三方接口或内部逻辑生成新Token
    return Token{
        Name:         "app-token",
        Value:        "new-valid-token-" + time.Now().Format(time.RFC3339),
        RefreshValue: "new-refresh-token-" + time.Now().Format(time.RFC3339),
        Expires:      time.Now().Add(24 * time.Hour),
    }, nil
}

4. 在Handler中使用安全Token

修改接口Handler,先获取有效Token再执行业务逻辑:

func GetEmployeesHandler(w http.ResponseWriter, r *http.Request) {
    // 获取有效Token
    validToken, err := GetValidToken()
    if err != nil {
        w.WriteHeader(http.StatusUnauthorized)
        fmt.Fprintf(w, "Token刷新失败: %v", err)
        return
    }

    // 这里可添加请求Token校验逻辑(比如对比请求头中的Authorization)
    reqToken := r.Header.Get("Authorization")
    if reqToken != "Bearer "+validToken.Value {
        w.WriteHeader(http.StatusUnauthorized)
        fmt.Fprintf(w, "无效的认证Token")
        return
    }

    // 执行业务逻辑
    w.WriteHeader(http.StatusOK)
    fmt.Fprintf(w, "API is up and running")
}

关键注意点

  • 并发安全:RWMutex允许多个goroutine同时读取Token,仅在刷新时加写锁,兼顾性能与安全性。
  • 双重检查:加锁前后两次校验Token状态,避免等待锁的goroutine重复执行刷新操作。
  • 提前过期检查:提前几分钟触发刷新,避免请求处理过程中Token突然过期导致请求失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 04:20:11