feat: Implement browser-based OAuth authentication using chromedp and rod, and add a team processing API.

This commit is contained in:
2026-02-02 05:05:07 +08:00
parent ee5b69af13
commit 4cd9f2b2b7
3 changed files with 66 additions and 122 deletions

View File

@@ -33,7 +33,6 @@ func CompleteWithChromedpLogged(authURL, email, password, teamID string, headles
}
}
logStep(StepBrowserStart, "正在启动 Chromedp 浏览器...")
// 获取随机浏览器配置
profile := GetRandomBrowserProfile()
@@ -80,8 +79,8 @@ func CompleteWithChromedpLogged(authURL, email, password, teamID string, headles
ctx, cancel := chromedp.NewContext(allocCtx)
defer cancel()
// 增加超时时间到 180 秒
ctx, cancel = context.WithTimeout(ctx, 180*time.Second)
// 设置合理的超时时间 30 秒
ctx, cancel = context.WithTimeout(ctx, 30*time.Second)
defer cancel()
var callbackURL string
@@ -150,17 +149,16 @@ func CompleteWithChromedpLogged(authURL, email, password, teamID string, headles
tasks = append([]chromedp.Action{fetch.Enable().WithHandleAuthRequests(true)}, tasks...)
}
logStep(StepNavigate, "正在访问授权页面...")
err := chromedp.Run(ctx, tasks...)
if err != nil {
logError(StepNavigate, "访问失败: %v", err)
logError(StepNavigate, "访问授权页失败: %v", err)
return "", fmt.Errorf("访问失败: %v", err)
}
time.Sleep(2 * time.Second)
if callbackURL != "" {
logStep(StepExtractCode, "已捕获授权码回调")
logStep(StepComplete, "授权成功(快速通道)")
return ExtractCodeFromCallbackURL(callbackURL), nil
}
@@ -168,21 +166,27 @@ func CompleteWithChromedpLogged(authURL, email, password, teamID string, headles
_ = chromedp.Run(ctx, chromedp.Location(&currentURL))
if strings.Contains(currentURL, "code=") {
logStep(StepComplete, "授权成功(快速通道)")
return ExtractCodeFromCallbackURL(currentURL), nil
}
time.Sleep(1 * time.Second)
// 邮箱输入框选择器
emailSelectors := []string{
`input[name="email"]`,
`input[type="email"]`,
`input[name="username"]`,
`input[id="email"]`,
`input[autocomplete="email"]`,
}
logStep(StepInputEmail, "正在查找邮箱输入框...")
// 创建带短超时的上下文用于查找元素10秒
findCtx, findCancel := context.WithTimeout(ctx, 10*time.Second)
var emailFilled bool
for _, sel := range emailSelectors {
err = chromedp.Run(ctx, chromedp.WaitVisible(sel, chromedp.ByQuery))
err = chromedp.Run(findCtx, chromedp.WaitVisible(sel, chromedp.ByQuery))
if err == nil {
err = chromedp.Run(ctx,
chromedp.Clear(sel, chromedp.ByQuery),
@@ -190,11 +194,11 @@ func CompleteWithChromedpLogged(authURL, email, password, teamID string, headles
)
if err == nil {
emailFilled = true
logStep(StepInputEmail, "已输入邮箱")
break
}
}
}
findCancel()
if !emailFilled {
logError(StepInputEmail, "未找到邮箱输入框")
@@ -208,9 +212,9 @@ func CompleteWithChromedpLogged(authURL, email, password, teamID string, headles
`button[data-testid="login-button"]`,
`button.continue-btn`,
`input[type="submit"]`,
`button[name="action"]`,
}
logStep(StepSubmitEmail, "正在提交邮箱...")
for _, sel := range buttonSelectors {
err = chromedp.Run(ctx, chromedp.Click(sel, chromedp.ByQuery))
if err == nil {
@@ -221,26 +225,31 @@ func CompleteWithChromedpLogged(authURL, email, password, teamID string, headles
time.Sleep(1500 * time.Millisecond)
if callbackURL != "" {
logStep(StepExtractCode, "已捕获授权码回调")
logStep(StepComplete, "授权成功")
return ExtractCodeFromCallbackURL(callbackURL), nil
}
_ = chromedp.Run(ctx, chromedp.Location(&currentURL))
if strings.Contains(currentURL, "code=") {
logStep(StepExtractCode, "已获取授权码")
logStep(StepComplete, "授权成功")
return ExtractCodeFromCallbackURL(currentURL), nil
}
logStep(StepInputPassword, "正在查找密码输入框...")
// 密码输入框选择器
passwordSelectors := []string{
`input[name="current-password"]`,
`input[name="password"]`,
`input[type="password"]`,
`input[name="password"]`,
`input[name="current-password"]`,
`input[id="password"]`,
`input[autocomplete="current-password"]`,
}
// 使用短超时查找密码框10秒
findCtx2, findCancel2 := context.WithTimeout(ctx, 10*time.Second)
var passwordFilled bool
for _, sel := range passwordSelectors {
err = chromedp.Run(ctx, chromedp.WaitVisible(sel, chromedp.ByQuery))
err = chromedp.Run(findCtx2, chromedp.WaitVisible(sel, chromedp.ByQuery))
if err == nil {
err = chromedp.Run(ctx,
chromedp.Clear(sel, chromedp.ByQuery),
@@ -248,11 +257,11 @@ func CompleteWithChromedpLogged(authURL, email, password, teamID string, headles
)
if err == nil {
passwordFilled = true
logStep(StepInputPassword, "已输入密码")
break
}
}
}
findCancel2()
if !passwordFilled {
logError(StepInputPassword, "未找到密码输入框")
@@ -261,7 +270,7 @@ func CompleteWithChromedpLogged(authURL, email, password, teamID string, headles
time.Sleep(300 * time.Millisecond)
logStep(StepSubmitPassword, "正在提交密码...")
logStep(StepSubmitPassword, "正在登录...")
for _, sel := range buttonSelectors {
err = chromedp.Run(ctx, chromedp.Click(sel, chromedp.ByQuery))
if err == nil {
@@ -269,23 +278,24 @@ func CompleteWithChromedpLogged(authURL, email, password, teamID string, headles
}
}
logStep(StepWaitCallback, "等待授权回调...")
// 等待授权回调最多15秒
for i := 0; i < 30; i++ {
time.Sleep(500 * time.Millisecond)
if callbackURL != "" {
logStep(StepComplete, "授权成功")
return ExtractCodeFromCallbackURL(callbackURL), nil
}
var url string
if err := chromedp.Run(ctx, chromedp.Location(&url)); err == nil {
if strings.Contains(url, "code=") {
logStep(StepExtractCode, "已获取授权码")
logStep(StepComplete, "授权成功")
return ExtractCodeFromCallbackURL(url), nil
}
if strings.Contains(url, "consent") {
logStep(StepConsent, "正在处理授权同意页面...")
logStep(StepConsent, "处理授权同意...")
for _, sel := range buttonSelectors {
err = chromedp.Run(ctx, chromedp.Click(sel, chromedp.ByQuery))
if err == nil {
@@ -296,7 +306,7 @@ func CompleteWithChromedpLogged(authURL, email, password, teamID string, headles
}
if strings.Contains(url, "authorize") && teamID != "" {
logStep(StepSelectWorkspace, "正在选择工作区: %s", teamID)
logStep(StepSelectWorkspace, "选择工作区...")
err = chromedp.Run(ctx,
chromedp.Click(fmt.Sprintf(`[data-workspace-id="%s"], [data-account-id="%s"]`, teamID, teamID), chromedp.ByQuery),
)
@@ -305,7 +315,7 @@ func CompleteWithChromedpLogged(authURL, email, password, teamID string, headles
}
if callbackURL != "" {
logStep(StepComplete, "授权成")
logStep(StepComplete, "授权成")
return ExtractCodeFromCallbackURL(callbackURL), nil
}