// // Copyright (C) 2024 veypi // 2025-07-24 15:27:31 // Distributed under terms of the MIT license. // package oauth import ( "github.com/veypi/OneAuth/cfg" "github.com/vyes/vigo" ) // RevokeRequest 撤销令牌请求参数 type RevokeRequest struct { Token string `form:"token" binding:"required"` TokenTypeHint string `form:"token_type_hint"` // access_token 或 refresh_token ClientID string `form:"client_id"` ClientSecret string `form:"client_secret"` } // RevokeResponse 撤销令牌响应 type RevokeResponse struct { Message string `json:"message"` Success bool `json:"success"` } // handleRevoke 处理OAuth撤销请求 func handleRevoke(x *vigo.X) error { args := &RevokeRequest{} if err := x.Parse(args); err != nil { return vigo.NewError("参数解析失败").WithError(err).WithCode(400) } if args.Token == "" { return vigo.NewError("令牌不能为空").WithCode(400) } db := cfg.DB() // 根据OAuth 2.0规范,撤销令牌应该是幂等操作 // 即使令牌不存在也应该返回成功,这是为了防止信息泄露 var revoked = false // 尝试撤销访问令牌 result := db.Model(&OAuthAccessToken{}).Where("token = ?", args.Token).Update("revoked", true) if result.Error == nil && result.RowsAffected > 0 { revoked = true } // 如果没有找到访问令牌,尝试撤销刷新令牌 if !revoked { result = db.Model(&OAuthRefreshToken{}).Where("token = ?", args.Token).Update("revoked", true) if result.Error == nil && result.RowsAffected > 0 { revoked = true } } // 根据OAuth 2.0规范,即使令牌不存在也返回成功 // 这样可以防止攻击者通过响应差异推断令牌是否存在 return x.JSON(&RevokeResponse{ Message: "令牌撤销成功", Success: true, }) }