feat: Add chromedp and rod-based OAuth authorization methods.

This commit is contained in:
2026-02-01 09:19:53 +08:00
parent 76ff32e83c
commit d05c19a8d5
2 changed files with 50 additions and 34 deletions

View File

@@ -49,41 +49,49 @@ func CompleteWithChromedp(authURL, email, password, teamID string, headless bool
ctx, cancel := chromedp.NewContext(allocCtx) ctx, cancel := chromedp.NewContext(allocCtx)
defer cancel() defer cancel()
ctx, cancel = context.WithTimeout(ctx, 120*time.Second) // 增加超时时间到 180 秒
ctx, cancel = context.WithTimeout(ctx, 180*time.Second)
defer cancel() defer cancel()
var callbackURL string var callbackURL string
chromedp.ListenTarget(ctx, func(ev interface{}) { // 只在代理需要认证时才启用 Fetch 域
switch ev := ev.(type) { if proxyServer != "" && proxyUser != "" {
case *fetch.EventRequestPaused: chromedp.ListenTarget(ctx, func(ev interface{}) {
// Fetch domain pauses requests; we must continue them to avoid stalling navigation. switch ev := ev.(type) {
reqID := ev.RequestID case *fetch.EventRequestPaused:
go func() { _ = fetch.ContinueRequest(reqID).Do(ctx) }() // Fetch domain pauses requests; we must continue them to avoid stalling navigation.
reqID := ev.RequestID
go func() { _ = fetch.ContinueRequest(reqID).Do(ctx) }()
case *fetch.EventAuthRequired: case *fetch.EventAuthRequired:
reqID := ev.RequestID reqID := ev.RequestID
source := fetch.AuthChallengeSourceServer source := fetch.AuthChallengeSourceServer
if ev.AuthChallenge != nil { if ev.AuthChallenge != nil {
source = ev.AuthChallenge.Source source = ev.AuthChallenge.Source
}
go func() {
resp := &fetch.AuthChallengeResponse{Response: fetch.AuthChallengeResponseResponseDefault}
if source == fetch.AuthChallengeSourceProxy {
if proxyUser != "" {
resp.Response = fetch.AuthChallengeResponseResponseProvideCredentials
resp.Username = proxyUser
resp.Password = proxyPass
} else {
// Fail fast if the proxy requires auth but user didn't provide credentials.
resp.Response = fetch.AuthChallengeResponseResponseCancelAuth
}
} }
_ = fetch.ContinueWithAuth(reqID, resp).Do(ctx)
}()
case *network.EventRequestWillBeSent: go func() {
resp := &fetch.AuthChallengeResponse{Response: fetch.AuthChallengeResponseResponseDefault}
if source == fetch.AuthChallengeSourceProxy {
if proxyUser != "" {
resp.Response = fetch.AuthChallengeResponseResponseProvideCredentials
resp.Username = proxyUser
resp.Password = proxyPass
} else {
// Fail fast if the proxy requires auth but user didn't provide credentials.
resp.Response = fetch.AuthChallengeResponseResponseCancelAuth
}
}
_ = fetch.ContinueWithAuth(reqID, resp).Do(ctx)
}()
}
})
}
// 监听回调 URL
chromedp.ListenTarget(ctx, func(ev interface{}) {
if ev, ok := ev.(*network.EventRequestWillBeSent); ok {
url := ev.Request.URL url := ev.Request.URL
if strings.Contains(url, "localhost") && strings.Contains(url, "code=") { if strings.Contains(url, "localhost") && strings.Contains(url, "code=") {
callbackURL = url callbackURL = url
@@ -91,13 +99,19 @@ func CompleteWithChromedp(authURL, email, password, teamID string, headless bool
} }
}) })
err := chromedp.Run(ctx, // 构建运行任务
// Handle proxy auth (407) in headless mode. tasks := []chromedp.Action{
fetch.Enable().WithHandleAuthRequests(true),
network.Enable(), network.Enable(),
chromedp.Navigate(authURL), chromedp.Navigate(authURL),
chromedp.WaitReady("body"), chromedp.WaitReady("body"),
) }
// 只在代理需要认证时才启用 Fetch 域
if proxyServer != "" && proxyUser != "" {
tasks = append([]chromedp.Action{fetch.Enable().WithHandleAuthRequests(true)}, tasks...)
}
err := chromedp.Run(ctx, tasks...)
if err != nil { if err != nil {
return "", fmt.Errorf("访问失败: %v", err) return "", fmt.Errorf("访问失败: %v", err)
} }

View File

@@ -123,7 +123,8 @@ func (r *RodAuth) Close() {
func (r *RodAuth) CompleteOAuth(authURL, email, password, teamID string) (string, error) { func (r *RodAuth) CompleteOAuth(authURL, email, password, teamID string) (string, error) {
// Handle proxy auth (407) in headless mode. // Handle proxy auth (407) in headless mode.
// When Fetch domain is enabled without patterns, requests will be paused and must be continued. // When Fetch domain is enabled without patterns, requests will be paused and must be continued.
if r.proxy != "" { // 只在代理需要认证时才启用 Fetch 域
if r.proxy != "" && r.proxyUser != "" {
authBrowser, cancel := r.browser.WithCancel() authBrowser, cancel := r.browser.WithCancel()
defer cancel() defer cancel()
@@ -160,7 +161,8 @@ func (r *RodAuth) CompleteOAuth(authURL, email, password, teamID string) (string
} }
defer page.Close() defer page.Close()
page = page.Timeout(45 * time.Second) // 增加超时时间到 90 秒
page = page.Timeout(90 * time.Second)
if err := page.Navigate(authURL); err != nil { if err := page.Navigate(authURL); err != nil {
return "", fmt.Errorf("访问授权URL失败: %v", err) return "", fmt.Errorf("访问授权URL失败: %v", err)