├── .gitignore ├── .vscode └── settings.json ├── README.md ├── api ├── get_login_openai_token.go ├── get_openai_token.go ├── refresh_openai_token.go └── revoke_openai_token.go ├── go.mod ├── public ├── login.html └── third.html └── vercel.json /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vercel 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ayuayue/chatgpt_token_vercel/ac9dd586e46f162a7dae1684c28a34bfbefa00fd/.vscode/settings.json -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 说明 2 | 3 | 官方文档: https://vercel.com/docs/concepts/functions/serverless-functions 4 | 5 | 这是一个部署在 vercel 上的 serverless,使用 go,js,或者其他语言来写。 6 | 7 | 所有的接口都要在 api 目录下。 8 | 9 | | 接口 | 说明 | 10 | |---------|---------| 11 | | / | 官网直登获取 Token 功能页面 | 12 | | /third | 第三方账号获取 Token 页面 | 13 | | /getOpenAItoken | 官网直登获取 Token 接口 | 14 | | /getOpenAItokenByCode | 通过 Code 获取 Token 接口 | 15 | | /revokeOpenAIToken | 撤销 refresh_token 接口 | 16 | | /refreshOpenAIToken | 刷新 Token 接口 | 17 | 18 | 19 | 部署地区:regions :sin1 新加坡 20 | 21 | 22 | 如果要部署官网直登的api接口,需要在 vercel 上设置环境变量,key 是 LoginURL,值就是自己部署的 pandora 项目域名,注意不要用 cf 的安全模式,不然没法直接调用,因为安全问题需要手动验证。 23 | 24 | 25 | Vercel 26 | [](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fayuayue%2Fchatgpt_token_vercel) -------------------------------------------------------------------------------- /api/get_login_openai_token.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "strings" 7 | "regexp" 8 | "os" 9 | "net/url" 10 | ) 11 | 12 | func GetLoginToken(w http.ResponseWriter, r *http.Request) { 13 | loginUrl := os.Getenv("LoginURL")+"/auth/login" 14 | method := "POST" 15 | params := url.Values{} 16 | params.Set("username", r.PostFormValue("username")) 17 | params.Set("password", r.PostFormValue("password")) 18 | params.Set("mfa_code", r.PostFormValue("mfa_code")) 19 | params.Set("action", "default") 20 | params.Set("next", "") 21 | payload := strings.NewReader(params.Encode()) 22 | fmt.Println(params.Encode()) 23 | 24 | client := &http.Client{ 25 | CheckRedirect: func(req *http.Request, via []*http.Request) error { 26 | return http.ErrUseLastResponse 27 | }, 28 | } 29 | 30 | req, err := http.NewRequest(method, loginUrl, payload) 31 | if err != nil { 32 | fmt.Fprint(w, err.Error()) 33 | return 34 | } 35 | req.Header.Add("User-Agent", "apifox/1.0.0 (https://www.apifox.cn)") 36 | req.Header.Add("Content-Type", "application/x-www-form-urlencoded") 37 | res, err := client.Do(req) 38 | if err != nil { 39 | fmt.Fprint(w, err) 40 | } 41 | defer res.Body.Close() 42 | 43 | 44 | // 获取重定向返回的 header 45 | redirectHeaders := res.Header 46 | 47 | // 将 header 转换为字符串 48 | var sb strings.Builder 49 | for key, values := range redirectHeaders { 50 | for _, value := range values { 51 | sb.WriteString(key) 52 | sb.WriteString(": ") 53 | sb.WriteString(value) 54 | sb.WriteString("\r\n") 55 | } 56 | } 57 | redirectHeadersStr := sb.String() 58 | 59 | 60 | // 使用正则表达式匹配 access_token 的内容 61 | regex := regexp.MustCompile(`access-token=(.*?);`) 62 | matches := regex.FindStringSubmatch(redirectHeadersStr) 63 | 64 | if len(matches) > 1 { 65 | accessToken := matches[1] 66 | fmt.Fprint(w, "Access Token:"+accessToken) 67 | } else { 68 | fmt.Fprint(w, "Access Token not found in the response.") 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /api/get_openai_token.go: -------------------------------------------------------------------------------- 1 | 2 | package api 3 | 4 | import ( 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | ) 10 | 11 | func GetToken(w http.ResponseWriter, r *http.Request) { 12 | url := "https://auth0.openai.com/oauth/token" 13 | method := "POST" 14 | code := r.PostFormValue("code") 15 | payload := `{ 16 | "redirect_uri": "com.openai.chat://auth0.openai.com/ios/com.openai.chat/callback", 17 | "grant_type": "authorization_code", 18 | "client_id": "pdlLIX2Y72MIl2rhLhTE9VV9bN905kBh", 19 | "code": "` + code + `", 20 | "code_verifier": "yGrXROHx_VazA0uovsxKfE263LMFcrSrdm4SlC-rob8" 21 | }` 22 | client := &http.Client{} 23 | req, err := http.NewRequest(method, url, strings.NewReader(payload)) 24 | 25 | if err != nil { 26 | fmt.Fprint(w, err.Error()) 27 | } 28 | req.Header.Add("User-Agent", "apifox/1.0.0 (https://www.apifox.cn)") 29 | req.Header.Add("Content-Type", "application/json") 30 | 31 | res, err := client.Do(req) 32 | if err != nil { 33 | fmt.Fprint(w, err) 34 | } 35 | defer res.Body.Close() 36 | 37 | body, err := ioutil.ReadAll(res.Body) 38 | if err != nil { 39 | fmt.Fprint(w, err.Error()) 40 | } 41 | fmt.Fprint(w, string(body)) 42 | } 43 | -------------------------------------------------------------------------------- /api/refresh_openai_token.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/http" 7 | "strings" 8 | ) 9 | 10 | func RefreshToken(w http.ResponseWriter, r *http.Request) { 11 | url := "https://auth0.openai.com/oauth/token" 12 | method := "POST" 13 | token := r.PostFormValue("refresh_token") 14 | payload := `{ 15 | "redirect_uri": "com.openai.chat://auth0.openai.com/ios/com.openai.chat/callback", 16 | "grant_type": "refresh_token", 17 | "client_id": "pdlLIX2Y72MIl2rhLhTE9VV9bN905kBh", 18 | "refresh_token": "` + token + `" 19 | }` 20 | client := &http.Client{} 21 | req, err := http.NewRequest(method, url, strings.NewReader(payload)) 22 | 23 | if err != nil { 24 | fmt.Fprint(w, err.Error()) 25 | } 26 | req.Header.Add("User-Agent", "apifox/1.0.0 (https://www.apifox.cn)") 27 | req.Header.Add("Content-Type", "application/json") 28 | 29 | res, err := client.Do(req) 30 | if err != nil { 31 | fmt.Fprint(w, err) 32 | } 33 | defer res.Body.Close() 34 | 35 | body, err := ioutil.ReadAll(res.Body) 36 | if err != nil { 37 | fmt.Fprint(w, err.Error()) 38 | } 39 | fmt.Fprint(w, string(body)) 40 | } 41 | -------------------------------------------------------------------------------- /api/revoke_openai_token.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/http" 7 | "strings" 8 | ) 9 | 10 | 11 | func RevokeToken(w http.ResponseWriter, r *http.Request) { 12 | url := "https://auth0.openai.com/oauth/revoke" 13 | method := "POST" 14 | token := r.PostFormValue("token") 15 | payload := `{ 16 | "client_id": "pdlLIX2Y72MIl2rhLhTE9VV9bN905kBh", 17 | "token": "` + token + `" 18 | }` 19 | client := &http.Client{} 20 | req, err := http.NewRequest(method, url, strings.NewReader(payload)) 21 | 22 | if err != nil { 23 | fmt.Fprint(w, err.Error()) 24 | } 25 | req.Header.Add("User-Agent", "apifox/1.0.0 (https://www.apifox.cn)") 26 | req.Header.Add("Content-Type", "application/json") 27 | 28 | res, err := client.Do(req) 29 | if err != nil { 30 | fmt.Fprint(w, err) 31 | } 32 | defer res.Body.Close() 33 | 34 | body, err := ioutil.ReadAll(res.Body) 35 | if err != nil { 36 | fmt.Fprint(w, err.Error()) 37 | } 38 | fmt.Fprint(w, string(body)) 39 | } 40 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module my-vercel-function 2 | 3 | go 1.19 4 | -------------------------------------------------------------------------------- /public/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |30 |
40 | 41 | 42 |43 | 返回信息:(只需要 access_token 即可登录) 44 |
53 | 本项目由 zhile.io 博客 指导 并由 vercel 部署完成。 54 |
55 |
27 | 1. 首先需要能正常登录 chat.openai.com 。然后点击下面的登录链接。
28 | 2. 然后在浏览器中打开开发者工具,切换到 Network 选项卡。
29 | 3. 登录后最后会卡住,并最后有一个重定向的请求,参数携带的有 code,并且只有一个 code 参数的那个请求才是。需要把 code 复制过来,获取 token。
30 | 4. 不会保存任何的信息,只充当一个调用工具,不做任何处理就返回原数据。
31 | 5. 获取token后,进入 Pandora 页面,并填写使用获取到的 access_token 登录即可。
32 |
点击跳转到登录页面 34 |
35 | 36 |37 |
43 | 44 | 45 |46 |
52 | 53 |54 |
60 | 61 |62 | 返回信息:(只需要 access_token 即可登录) 63 |
67 | 本项目由 zhile.io 博客 指导 并由 vercel 部署完成。 68 |
69 |