feat(backend): 扩展 Gemini OAuth Repository 层

- 更新 gemini_oauth_client.go: 支持 AI Studio OAuth 客户端
- 更新 geminicli_codeassist_client.go: 适配新的认证流程
This commit is contained in:
ianshaw
2025-12-25 21:24:35 -08:00
parent 50734c5edc
commit 2d6e1d26c0
2 changed files with 36 additions and 6 deletions

View File

@@ -28,10 +28,20 @@ func NewGeminiOAuthClient(cfg *config.Config) ports.GeminiOAuthClient {
func (c *geminiOAuthClient) ExchangeCode(ctx context.Context, code, codeVerifier, redirectURI, proxyURL string) (*geminicli.TokenResponse, error) { func (c *geminiOAuthClient) ExchangeCode(ctx context.Context, code, codeVerifier, redirectURI, proxyURL string) (*geminicli.TokenResponse, error) {
client := createGeminiReqClient(proxyURL) client := createGeminiReqClient(proxyURL)
// Both Code Assist and AI Studio OAuth use the same token endpoint and OAuth client.
oauthCfg, err := geminicli.EffectiveOAuthConfig(geminicli.OAuthConfig{
ClientID: c.cfg.Gemini.OAuth.ClientID,
ClientSecret: c.cfg.Gemini.OAuth.ClientSecret,
Scopes: c.cfg.Gemini.OAuth.Scopes,
}, "code_assist")
if err != nil {
return nil, err
}
formData := url.Values{} formData := url.Values{}
formData.Set("grant_type", "authorization_code") formData.Set("grant_type", "authorization_code")
formData.Set("client_id", c.cfg.Gemini.OAuth.ClientID) formData.Set("client_id", oauthCfg.ClientID)
formData.Set("client_secret", c.cfg.Gemini.OAuth.ClientSecret) formData.Set("client_secret", oauthCfg.ClientSecret)
formData.Set("code", code) formData.Set("code", code)
formData.Set("code_verifier", codeVerifier) formData.Set("code_verifier", codeVerifier)
formData.Set("redirect_uri", redirectURI) formData.Set("redirect_uri", redirectURI)
@@ -54,11 +64,21 @@ func (c *geminiOAuthClient) ExchangeCode(ctx context.Context, code, codeVerifier
func (c *geminiOAuthClient) RefreshToken(ctx context.Context, refreshToken, proxyURL string) (*geminicli.TokenResponse, error) { func (c *geminiOAuthClient) RefreshToken(ctx context.Context, refreshToken, proxyURL string) (*geminicli.TokenResponse, error) {
client := createGeminiReqClient(proxyURL) client := createGeminiReqClient(proxyURL)
// Both Code Assist and AI Studio OAuth use the same token endpoint and OAuth client.
oauthCfg, err := geminicli.EffectiveOAuthConfig(geminicli.OAuthConfig{
ClientID: c.cfg.Gemini.OAuth.ClientID,
ClientSecret: c.cfg.Gemini.OAuth.ClientSecret,
Scopes: c.cfg.Gemini.OAuth.Scopes,
}, "code_assist")
if err != nil {
return nil, err
}
formData := url.Values{} formData := url.Values{}
formData.Set("grant_type", "refresh_token") formData.Set("grant_type", "refresh_token")
formData.Set("refresh_token", refreshToken) formData.Set("refresh_token", refreshToken)
formData.Set("client_id", c.cfg.Gemini.OAuth.ClientID) formData.Set("client_id", oauthCfg.ClientID)
formData.Set("client_secret", c.cfg.Gemini.OAuth.ClientSecret) formData.Set("client_secret", oauthCfg.ClientSecret)
var tokenResp geminicli.TokenResponse var tokenResp geminicli.TokenResponse
resp, err := client.R(). resp, err := client.R().

View File

@@ -34,11 +34,15 @@ func (c *geminiCliCodeAssistClient) LoadCodeAssist(ctx context.Context, accessTo
SetSuccessResult(&out). SetSuccessResult(&out).
Post(c.baseURL + "/v1internal:loadCodeAssist") Post(c.baseURL + "/v1internal:loadCodeAssist")
if err != nil { if err != nil {
fmt.Printf("[CodeAssist] LoadCodeAssist request error: %v\n", err)
return nil, fmt.Errorf("request failed: %w", err) return nil, fmt.Errorf("request failed: %w", err)
} }
if !resp.IsSuccessState() { if !resp.IsSuccessState() {
return nil, fmt.Errorf("loadCodeAssist failed: status %d, body: %s", resp.StatusCode, geminicli.SanitizeBodyForLogs(resp.String())) body := geminicli.SanitizeBodyForLogs(resp.String())
fmt.Printf("[CodeAssist] LoadCodeAssist failed: status %d, body: %s\n", resp.StatusCode, body)
return nil, fmt.Errorf("loadCodeAssist failed: status %d, body: %s", resp.StatusCode, body)
} }
fmt.Printf("[CodeAssist] LoadCodeAssist success: status %d, response: %+v\n", resp.StatusCode, out)
return &out, nil return &out, nil
} }
@@ -47,6 +51,8 @@ func (c *geminiCliCodeAssistClient) OnboardUser(ctx context.Context, accessToken
reqBody = defaultOnboardUserRequest() reqBody = defaultOnboardUserRequest()
} }
fmt.Printf("[CodeAssist] OnboardUser request body: %+v\n", reqBody)
var out geminicli.OnboardUserResponse var out geminicli.OnboardUserResponse
resp, err := createGeminiCliReqClient(proxyURL).R(). resp, err := createGeminiCliReqClient(proxyURL).R().
SetContext(ctx). SetContext(ctx).
@@ -57,11 +63,15 @@ func (c *geminiCliCodeAssistClient) OnboardUser(ctx context.Context, accessToken
SetSuccessResult(&out). SetSuccessResult(&out).
Post(c.baseURL + "/v1internal:onboardUser") Post(c.baseURL + "/v1internal:onboardUser")
if err != nil { if err != nil {
fmt.Printf("[CodeAssist] OnboardUser request error: %v\n", err)
return nil, fmt.Errorf("request failed: %w", err) return nil, fmt.Errorf("request failed: %w", err)
} }
if !resp.IsSuccessState() { if !resp.IsSuccessState() {
return nil, fmt.Errorf("onboardUser failed: status %d, body: %s", resp.StatusCode, geminicli.SanitizeBodyForLogs(resp.String())) body := geminicli.SanitizeBodyForLogs(resp.String())
fmt.Printf("[CodeAssist] OnboardUser failed: status %d, body: %s\n", resp.StatusCode, body)
return nil, fmt.Errorf("onboardUser failed: status %d, body: %s", resp.StatusCode, body)
} }
fmt.Printf("[CodeAssist] OnboardUser success: status %d, response: %+v\n", resp.StatusCode, out)
return &out, nil return &out, nil
} }