如何在Go Google API刷新AccessToken和RefreshToken时接收通知?
在Go Google API中监听Token变更并持久化到数据库
当使用Go Google API库时,要在Token自动刷新后将新Token同步到数据库,核心是通过**自定义oauth2.TokenSource**拦截Token的获取/刷新操作,在拿到新Token时触发持久化逻辑。
实现步骤
- 定义包装类实现
oauth2.TokenSource接口,拦截Token获取结果并触发保存逻辑:
import ( "context" "golang.org/x/oauth2" "golang.org/x/oauth2/google" "google.golang.org/api/drive/v3" "time" ) // 自定义TokenSource,用于在Token更新时保存到数据库 type savingTokenSource struct { oauth2.TokenSource // 嵌套原始TokenSource,继承其自动刷新逻辑 saveFunc func(*oauth2.Token) error // 数据库保存回调 } // Token 重写Token方法,拦截Token获取流程 func (s *savingTokenSource) Token() (*oauth2.Token, error) { // 调用原始TokenSource获取Token(自动处理过期刷新) token, err := s.TokenSource.Token() if err != nil { return nil, err } // 将新Token同步到数据库 if err := s.saveFunc(token); err != nil { return nil, err } return token, nil }
- 构建自定义TokenSource并创建API客户端:
func main() { // 1. 从数据库读取用户初始Token initialToken := &oauth2.Token{ AccessToken: "用户已存的AccessToken", RefreshToken: "用户已存的RefreshToken", Expiry: time.Now().Add(-time.Hour), // 模拟Token过期状态 } // 2. 配置OAuth2基础参数 config := &oauth2.Config{ ClientID: "你的客户端ID", ClientSecret: "你的客户端密钥", RedirectURL: "你的回调地址", Scopes: []string{drive.DriveFileScope}, // 根据业务需求设置权限范围 Endpoint: google.Endpoint, } // 3. 创建原始TokenSource(自带自动刷新逻辑) originalTS := config.TokenSource(context.Background(), initialToken) // 4. 实现Token保存到数据库的逻辑(替换为你的实际数据库操作) saveToDB := func(token *oauth2.Token) error { // 示例:更新数据库中对应用户的Token记录 // _, err := db.Exec("UPDATE users SET access_token=?, refresh_token=?, expiry=? WHERE id=?", // token.AccessToken, token.RefreshToken, token.Expiry, userID) // return err return nil } // 5. 包装为带缓存+保存逻辑的TokenSource,避免重复刷新和无效写入 cachedTS := oauth2.ReuseTokenSource(initialToken, originalTS) savingTS := &savingTokenSource{ TokenSource: cachedTS, saveFunc: saveToDB, } // 6. 创建带自定义TokenSource的HTTP客户端 client := oauth2.NewClient(context.Background(), savingTS) // 7. 创建Google API服务(以Drive为例) driveSvc, err := drive.New(client) if err != nil { panic(err) } // 后续使用driveSvc发起请求时,Token过期会自动刷新,新Token会同步到数据库 }
关键注意事项
ReuseTokenSource会缓存有效Token,仅当Token过期时触发刷新,减少不必要的网络请求和数据库操作。- 保存Token时建议做幂等校验:对比数据库中现有Token,仅当AccessToken/RefreshToken/Expiry发生变化时执行更新,降低数据库写入压力。
- 并发场景处理:若多个请求同时触发Token刷新,可能导致重复保存,可通过加锁或数据库乐观锁避免冲突。
谷歌官方文档(OAuth2 Web服务器流程-离线访问)翻译
当应用需要在用户未主动操作的情况下访问Google API时,必须请求离线访问权限。此时Google会返回刷新令牌,应用可通过该令牌获取新的访问令牌,无需用户再次授权:
- 请求离线访问时,需在构建授权URL时添加
access_type=offline参数。 - 若用户已授权过应用,但之前未请求离线访问,再次发起授权时需添加
prompt=consent参数,才能获取刷新令牌。
内容的提问来源于stack exchange,提问作者Maggie Grace
相关产品推荐
相关产品推荐

