Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion backend/internal/handler/admin/antigravity_oauth_handler.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package admin

import (
"fmt"
"strings"

"github.com/Wei-Shaw/sub2api/internal/pkg/response"
"github.com/Wei-Shaw/sub2api/internal/service"
"github.com/gin-gonic/gin"
Expand All @@ -27,7 +30,8 @@ func (h *AntigravityOAuthHandler) GenerateAuthURL(c *gin.Context) {
return
}

result, err := h.antigravityOAuthService.GenerateAuthURL(c.Request.Context(), req.ProxyID)
redirectURI := deriveRedirectURI(c)
result, err := h.antigravityOAuthService.GenerateAuthURL(c.Request.Context(), req.ProxyID, redirectURI)
if err != nil {
response.InternalError(c, "生成授权链接失败: "+err.Error())
return
Expand Down Expand Up @@ -65,3 +69,25 @@ func (h *AntigravityOAuthHandler) ExchangeCode(c *gin.Context) {

response.Success(c, tokenInfo)
}

func deriveRedirectURI(c *gin.Context) string {
origin := strings.TrimSpace(c.GetHeader("Origin"))
if origin != "" {
return strings.TrimRight(origin, "/") + "/auth/callback"
}

scheme := "http"
if c.Request.TLS != nil {
scheme = "https"
}
if xfProto := strings.TrimSpace(c.GetHeader("X-Forwarded-Proto")); xfProto != "" {
scheme = strings.TrimSpace(strings.Split(xfProto, ",")[0])
}

host := strings.TrimSpace(c.Request.Host)
if xfHost := strings.TrimSpace(c.GetHeader("X-Forwarded-Host")); xfHost != "" {
host = strings.TrimSpace(strings.Split(xfHost, ",")[0])
}

return fmt.Sprintf("%s://%s/auth/callback", scheme, host)
}
4 changes: 2 additions & 2 deletions backend/internal/pkg/antigravity/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,12 +186,12 @@ func shouldFallbackToNextURL(err error, statusCode int) bool {
}

// ExchangeCode 用 authorization code 交换 token
func (c *Client) ExchangeCode(ctx context.Context, code, codeVerifier string) (*TokenResponse, error) {
func (c *Client) ExchangeCode(ctx context.Context, code, codeVerifier, redirectURI string) (*TokenResponse, error) {
params := url.Values{}
params.Set("client_id", ClientID)
params.Set("client_secret", ClientSecret)
params.Set("code", code)
params.Set("redirect_uri", RedirectURI)
params.Set("redirect_uri", redirectURI)
params.Set("grant_type", "authorization_code")
params.Set("code_verifier", codeVerifier)

Expand Down
12 changes: 8 additions & 4 deletions backend/internal/pkg/antigravity/oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ const (
ClientID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com"
ClientSecret = "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"

// 固定的 redirect_uri(用户需手动复制 code)
RedirectURI = "http://localhost:8085/callback"
// Default RedirectURI (can be overridden)
DefaultRedirectURI = "http://localhost:8085/callback"

// OAuth scopes
Scopes = "https://www.googleapis.com/auth/cloud-platform " +
Expand Down Expand Up @@ -133,6 +133,7 @@ type OAuthSession struct {
State string `json:"state"`
CodeVerifier string `json:"code_verifier"`
ProxyURL string `json:"proxy_url,omitempty"`
RedirectURI string `json:"redirect_uri,omitempty"`
CreatedAt time.Time `json:"created_at"`
}

Expand Down Expand Up @@ -248,10 +249,13 @@ func base64URLEncode(data []byte) string {
}

// BuildAuthorizationURL 构建 Google OAuth 授权 URL
func BuildAuthorizationURL(state, codeChallenge string) string {
func BuildAuthorizationURL(state, codeChallenge, redirectURI string) string {
if redirectURI == "" {
redirectURI = DefaultRedirectURI
}
params := url.Values{}
params.Set("client_id", ClientID)
params.Set("redirect_uri", RedirectURI)
params.Set("redirect_uri", redirectURI)
params.Set("response_type", "code")
params.Set("scope", Scopes)
params.Set("state", state)
Expand Down
12 changes: 9 additions & 3 deletions backend/internal/service/antigravity_oauth_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ type AntigravityAuthURLResult struct {
}

// GenerateAuthURL 生成 Google OAuth 授权链接
func (s *AntigravityOAuthService) GenerateAuthURL(ctx context.Context, proxyID *int64) (*AntigravityAuthURLResult, error) {
func (s *AntigravityOAuthService) GenerateAuthURL(ctx context.Context, proxyID *int64, redirectURI string) (*AntigravityAuthURLResult, error) {
state, err := antigravity.GenerateState()
if err != nil {
return nil, fmt.Errorf("生成 state 失败: %w", err)
Expand Down Expand Up @@ -58,12 +58,13 @@ func (s *AntigravityOAuthService) GenerateAuthURL(ctx context.Context, proxyID *
State: state,
CodeVerifier: codeVerifier,
ProxyURL: proxyURL,
RedirectURI: redirectURI,
CreatedAt: time.Now(),
}
s.sessionStore.Set(sessionID, session)

codeChallenge := antigravity.GenerateCodeChallenge(codeVerifier)
authURL := antigravity.BuildAuthorizationURL(state, codeChallenge)
authURL := antigravity.BuildAuthorizationURL(state, codeChallenge, redirectURI)

return &AntigravityAuthURLResult{
AuthURL: authURL,
Expand Down Expand Up @@ -103,6 +104,11 @@ func (s *AntigravityOAuthService) ExchangeCode(ctx context.Context, input *Antig
return nil, fmt.Errorf("state 无效")
}

redirectURI := session.RedirectURI
if redirectURI == "" {
redirectURI = antigravity.DefaultRedirectURI
}

// 确定代理 URL
proxyURL := session.ProxyURL
if input.ProxyID != nil {
Expand All @@ -115,7 +121,7 @@ func (s *AntigravityOAuthService) ExchangeCode(ctx context.Context, input *Antig
client := antigravity.NewClient(proxyURL)

// 交换 token
tokenResp, err := client.ExchangeCode(ctx, input.Code, session.CodeVerifier)
tokenResp, err := client.ExchangeCode(ctx, input.Code, session.CodeVerifier, redirectURI)
if err != nil {
return nil, fmt.Errorf("token 交换失败: %w", err)
}
Expand Down