编程指南社区OAuth 2.0 接入文档

余胜军说java助理
2026-03-20 16:26
阅读 340

OAuth 2.0 接入文档

编程指南开放平台提供 OAuth 2.0 授权登录能力,允许第三方网站引导用户使用编程指南账号进行登录,获取用户基本信息。

简介

编程指南 OAuth 2.0 授权登录采用标准的 Authorization Code(授权码) 模式。第三方应用接入后,用户可以在你的网站上通过编程指南账号一键登录,无需再次注册。

授权成功后,你的应用可以获取到以下用户信息:

  • 用户唯一标识(uid)
  • 用户昵称(nickname)
  • 用户头像(avatar)
  • 用户简介(desc)

术语说明

术语 说明
client_id 应用唯一标识,创建应用后获得
client_secret 应用密钥,创建应用时获得(仅显示一次),用于后端换取 token
redirect_uri 授权回调地址,用户授权成功后跳转的地址
authorization_code 授权码(code),用户同意授权后生成,有效期 5 分钟,一次性使用
access_token 访问令牌,调用接口的凭证,有效期 2 小时
refresh_token 刷新令牌,用于续期 access_token,有效期 30 天
scope 授权范围,当前支持 user_info(获取用户基本信息)

授权流程

整体流程

用户点击登录 → 跳转编程指南授权页 → 用户同意授权 → 回调你的网站(带 code) → 后端用 code 换 token → 获取用户信息

注意: code 换 token 以及获取用户信息必须在 你的服务端 完成,不要在前端暴露 client_secret。


第一步:引导用户授权

在你的网站登录页面放置「使用编程指南登录」按钮,用户点击后跳转到编程指南授权页面。

请求地址

https://code-guide.vip/oauth/consent

请求方式

GET 浏览器跳转(Query 参数)

请求 Header

该接口为浏览器跳转,无需设置请求头。

请求参数

字段 类型 必填 描述
client_id string 应用唯一标识
redirect_uri string 授权回调地址,需与创建应用时填写的一致,需做 URL 编码
response_type string 固定值 code
scope string 授权范围,固定值 user_info
state string 推荐 随机字符串,用于防止 CSRF 攻击,授权完成后会原样返回

请求示例

https://code-guide.vip/oauth/consent?client_id=your_client_id&redirect_uri=https%3A%2F%2Fyoursite.com%2Fcallback&response_type=code&scope=user_info&state=random_string

应答参数

该接口为浏览器跳转,用户同意授权后会重定向到你的 redirect_uri,并在 URL 中携带以下参数:

字段 类型 描述
code string 授权码,有效期 5 分钟,一次性使用
state string 你传入的 state 参数,原样返回

应答示例

授权成功回调:

https://yoursite.com/callback?code=AUTHORIZATION_CODE&state=random_string

用户拒绝授权:

https://yoursite.com/callback?error=access_denied&state=random_string

第二步:获取授权码

用户在编程指南授权页同意授权后,浏览器会被重定向到你填写的 redirect_uri,并携带 codestate 参数。

回调地址

https://yoursite.com/callback(你在创建应用时填写的 redirect_uri)

回调方式

GET 浏览器 302 重定向(Query 参数)

回调参数

字段 类型 描述
code string 授权码,有效期 5 分钟,一次性使用。获取后需立即在服务端换取 access_token
state string 第一步传入的 state 参数,原样返回,用于防止 CSRF 攻击
error string 错误码(仅用户拒绝授权时返回),值为 access_denied

注意: 授权码 code 有效期为 5 分钟,且只能使用一次。请在获取后立即在服务端换取 access_token。

回调示例

授权成功:

https://yoursite.com/callback?code=AUTHORIZATION_CODE&state=random_string

用户拒绝授权:

https://yoursite.com/callback?error=access_denied&state=random_string

前端处理示例

// 在你的 callback 页面解析回调参数
const params = new URLSearchParams(window.location.search);
const code = params.get('code');
const state = params.get('state');
const error = params.get('error');

// 验证 state 防止 CSRF
const savedState = sessionStorage.getItem('oauth_state');
if (state !== savedState) {
  alert('安全验证失败');
  return;
}

if (error) {
  console.log('用户拒绝授权:', error);
  return;
}

if (code) {
  fetch('/api/auth/code-guide/callback', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ code, state })
  })
  .then(res => res.json())
  .then(data => console.log('登录成功:', data));
}

第三步:获取访问令牌

在你的 服务端,使用授权码 code 换取 access_token。

请求地址

https://api.code-guide.autogptai.club/oauth/token

请求方式

POST Request-Body(application/x-www-form-urlencoded)

请求 Header

字段 类型 描述
Content-Type string 请求消息类型,固定值:application/x-www-form-urlencoded

请求参数

字段 类型 必填 描述
grant_type string 固定值 authorization_code
code string 上一步获取的授权码
client_id string 应用唯一标识
client_secret string 应用密钥
redirect_uri string 授权回调地址,需与第一步一致

请求示例

curl -X POST https://api.code-guide.autogptai.club/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=AUTHORIZATION_CODE" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "redirect_uri=https://yoursite.com/callback"

应答参数

字段 类型 描述
code number 返回码,1 表示成功,0 表示失败
msg string 返回信息
data object 返回数据对象
access_token string 访问令牌,有效期 2 小时
token_type string 令牌类型,固定值 Bearer
expires_in number 过期时间,单位:秒(默认 7200)
refresh_token string 刷新令牌,有效期 30 天
scope string 授权范围

应答示例

成功响应:

{
  "code": 1,
  "msg": "success",
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIs...",
    "token_type": "Bearer",
    "expires_in": 7200,
    "refresh_token": "a1b2c3d4e5f6...",
    "scope": "user_info"
  }
}

失败响应:

{
  "code": 0,
  "msg": "invalid authorization code",
  "data": null
}

注意: code 换 token 必须在 你的服务端 完成,不要在前端暴露 client_secret。


第四步:获取用户信息

使用 access_token 调用以下接口获取用户基本信息。

请求地址

https://api.code-guide.autogptai.club/oauth/userinfo

请求方式

GET

请求 Header

字段 类型 描述
Authorization string 授权 Access-Token,格式:Bearer {access_token},获取方法见第三步

请求参数

该接口无需请求参数,仅通过 Header 中的 Access-Token 鉴权。

请求示例

curl https://api.code-guide.autogptai.club/oauth/userinfo \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

应答参数

字段 类型 描述
code number 返回码,1 表示成功,0 表示失败
msg string 返回信息
data object 用户信息对象
uid number 用户唯一标识
nickname string 用户昵称
avatar string 用户头像 URL
desc string 用户个人简介

应答示例

成功响应:

{
  "code": 1,
  "msg": "success",
  "data": {
    "uid": 10001,
    "nickname": "张三",
    "avatar": "https://xxx/avatar.jpg",
    "desc": "全栈开发者"
  }
}

失败响应:

{
  "code": 0,
  "msg": "invalid or expired access_token",
  "data": null
}

API 参考

所有 API 的基础地址为 https://api.code-guide.autogptai.club。响应格式统一为:{ "code": 1, "msg": "success", "data": ... },其中 code=1 表示成功,code=0 表示失败。


获取 Access Token

请求地址

https://api.code-guide.autogptai.club/oauth/token

请求方式

POST Request-Body(application/x-www-form-urlencoded)

请求 Header

字段 类型 描述
Content-Type string 请求消息类型,固定值:application/x-www-form-urlencoded

请求参数

字段 类型 必填 描述
grant_type string 固定值 authorization_code
code string 用户授权后获取的授权码,有效期 5 分钟,一次性使用
client_id string 应用唯一标识
client_secret string 应用密钥
redirect_uri string 授权回调地址,需与第一步一致

请求示例

curl -X POST https://api.code-guide.autogptai.club/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=AUTHORIZATION_CODE" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "redirect_uri=https://yoursite.com/callback"
import requests

url = "https://api.code-guide.autogptai.club/oauth/token"
data = {
    "grant_type": "authorization_code",
    "code": "AUTHORIZATION_CODE",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
    "redirect_uri": "https://yoursite.com/callback"
}

response = requests.post(url, data=data)
print(response.json())
const response = await fetch(
  'https://api.code-guide.autogptai.club/oauth/token',
  {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      code: 'AUTHORIZATION_CODE',
      client_id: 'YOUR_CLIENT_ID',
      client_secret: 'YOUR_CLIENT_SECRET',
      redirect_uri: 'https://yoursite.com/callback'
    })
  }
);
const result = await response.json();
console.log(result);
import java.net.http.*;
import java.net.URI;

HttpClient client = HttpClient.newHttpClient();
String body = "grant_type=authorization_code"
    + "&code=AUTHORIZATION_CODE"
    + "&client_id=YOUR_CLIENT_ID"
    + "&client_secret=YOUR_CLIENT_SECRET"
    + "&redirect_uri=https://yoursite.com/callback";

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.code-guide.autogptai.club/oauth/token"))
    .header("Content-Type", "application/x-www-form-urlencoded")
    .POST(HttpRequest.BodyPublishers.ofString(body))
    .build();

HttpResponse<String> response = client.send(request,
    HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());

应答参数

字段 类型 描述
code number 返回码,1 表示成功,0 表示失败
msg string 返回信息
data object 返回数据对象
access_token string 访问令牌,有效期 2 小时
token_type string 令牌类型,固定值 Bearer
expires_in number 过期时间,单位:秒(默认 7200)
refresh_token string 刷新令牌,有效期 30 天
scope string 授权范围

应答示例

成功响应:

{
  "code": 1,
  "msg": "success",
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIs...",
    "token_type": "Bearer",
    "expires_in": 7200,
    "refresh_token": "a1b2c3d4e5f6...",
    "scope": "user_info"
  }
}

失败响应:

{
  "code": 0,
  "msg": "invalid authorization code",
  "data": null
}

获取用户信息

请求地址

https://api.code-guide.autogptai.club/oauth/userinfo

请求方式

GET

请求 Header

字段 类型 描述
Authorization string 授权 Access-Token,格式:Bearer {access_token},获取方法见接口【获取 Access Token】

请求参数

该接口无需请求参数,仅通过 Header 中的 Access-Token 鉴权。

请求示例

curl https://api.code-guide.autogptai.club/oauth/userinfo \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
import requests

url = "https://api.code-guide.autogptai.club/oauth/userinfo"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN"
}

response = requests.get(url, headers=headers)
print(response.json())
const response = await fetch(
  'https://api.code-guide.autogptai.club/oauth/userinfo',
  {
    headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN' }
  }
);
const result = await response.json();
console.log(result);
import java.net.http.*;
import java.net.URI;

HttpClient client = HttpClient.newHttpClient();

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.code-guide.autogptai.club/oauth/userinfo"))
    .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .GET()
    .build();

HttpResponse<String> response = client.send(request,
    HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());

应答参数

字段 类型 描述
code number 返回码,1 表示成功,0 表示失败
msg string 返回信息
data object 用户信息对象
uid number 用户唯一标识
nickname string 用户昵称
avatar string 用户头像 URL
desc string 用户个人简介

应答示例

成功响应:

{
  "code": 1,
  "msg": "success",
  "data": {
    "uid": 10001,
    "nickname": "张三",
    "avatar": "https://xxx/avatar.jpg",
    "desc": "全栈开发者"
  }
}

失败响应:

{
  "code": 0,
  "msg": "invalid or expired access_token",
  "data": null
}

刷新 Access Token

access_token 过期后,使用 refresh_token 获取新的 access_token,无需用户重新授权。

请求地址

https://api.code-guide.autogptai.club/oauth/token/refresh

请求方式

POST Request-Body(application/x-www-form-urlencoded)

请求 Header

字段 类型 描述
Content-Type string 请求消息类型,固定值:application/x-www-form-urlencoded

请求参数

字段 类型 必填 描述
refresh_token string 之前获取的 refresh_token
client_id string 应用唯一标识
client_secret string 应用密钥

请求示例

curl -X POST https://api.code-guide.autogptai.club/oauth/token/refresh \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "refresh_token=YOUR_REFRESH_TOKEN" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET"
import requests

url = "https://api.code-guide.autogptai.club/oauth/token/refresh"
data = {
    "refresh_token": "YOUR_REFRESH_TOKEN",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET"
}

response = requests.post(url, data=data)
print(response.json())
const response = await fetch(
  'https://api.code-guide.autogptai.club/oauth/token/refresh',
  {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      refresh_token: 'YOUR_REFRESH_TOKEN',
      client_id: 'YOUR_CLIENT_ID',
      client_secret: 'YOUR_CLIENT_SECRET'
    })
  }
);
const result = await response.json();
console.log(result);
import java.net.http.*;
import java.net.URI;

HttpClient client = HttpClient.newHttpClient();
String body = "refresh_token=YOUR_REFRESH_TOKEN"
    + "&client_id=YOUR_CLIENT_ID"
    + "&client_secret=YOUR_CLIENT_SECRET";

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.code-guide.autogptai.club/oauth/token/refresh"))
    .header("Content-Type", "application/x-www-form-urlencoded")
    .POST(HttpRequest.BodyPublishers.ofString(body))
    .build();

HttpResponse<String> response = client.send(request,
    HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());

应答参数

字段 类型 描述
code number 返回码,1 表示成功,0 表示失败
msg string 返回信息
data object 返回数据对象
access_token string 新的访问令牌,有效期 2 小时
token_type string 令牌类型,固定值 Bearer
expires_in number 过期时间,单位:秒(默认 7200)
refresh_token string 新的刷新令牌(滚动刷新),有效期 30 天
scope string 授权范围

应答示例

成功响应:

{
  "code": 1,
  "msg": "success",
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIs...(new)",
    "token_type": "Bearer",
    "expires_in": 7200,
    "refresh_token": "x9y8z7w6v5u4...(new)",
    "scope": "user_info"
  }
}

失败响应:

{
  "code": 0,
  "msg": "invalid or expired refresh_token",
  "data": null
}

撤销令牌

当用户退出登录或解除绑定时,应主动撤销令牌。

请求地址

https://api.code-guide.autogptai.club/oauth/token/revoke

请求方式

POST Request-Body(application/x-www-form-urlencoded)

请求 Header

字段 类型 描述
Content-Type string 请求消息类型,固定值:application/x-www-form-urlencoded

请求参数

字段 类型 必填 描述
token string 要撤销的令牌(access_token 或 refresh_token)
client_id string 应用唯一标识
client_secret string 应用密钥

请求示例

curl -X POST https://api.code-guide.autogptai.club/oauth/token/revoke \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "token=ACCESS_TOKEN_OR_REFRESH_TOKEN" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET"
import requests

url = "https://api.code-guide.autogptai.club/oauth/token/revoke"
data = {
    "token": "ACCESS_TOKEN_OR_REFRESH_TOKEN",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET"
}

response = requests.post(url, data=data)
print(response.json())
const response = await fetch(
  'https://api.code-guide.autogptai.club/oauth/token/revoke',
  {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      token: 'ACCESS_TOKEN_OR_REFRESH_TOKEN',
      client_id: 'YOUR_CLIENT_ID',
      client_secret: 'YOUR_CLIENT_SECRET'
    })
  }
);
const result = await response.json();
console.log(result);
import java.net.http.*;
import java.net.URI;

HttpClient client = HttpClient.newHttpClient();
String body = "token=ACCESS_TOKEN_OR_REFRESH_TOKEN"
    + "&client_id=YOUR_CLIENT_ID"
    + "&client_secret=YOUR_CLIENT_SECRET";

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.code-guide.autogptai.club/oauth/token/revoke"))
    .header("Content-Type", "application/x-www-form-urlencoded")
    .POST(HttpRequest.BodyPublishers.ofString(body))
    .build();

HttpResponse<String> response = client.send(request,
    HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());

应答参数

字段 类型 描述
code number 返回码,1 表示成功,0 表示失败
msg string 返回信息
data null 该接口无返回数据

应答示例

成功响应:

{
  "code": 1,
  "msg": "success",
  "data": null
}

失败响应:

{
  "code": 0,
  "msg": "invalid token",
  "data": null
}

快速开始

创建应用

  1. 登录编程指南,进入 设置 → 开发者中心
  2. 点击「创建应用」,填写应用名称、Logo、简介和回调地址
  3. 创建成功后,妥善保存 Client ID 和 Client Secret(Secret 仅显示一次)
  4. 在你的网站登录页添加「使用编程指南登录」按钮

安全提醒: Client Secret 是应用的重要凭证,请勿在前端代码、版本控制或公开场合暴露。

前端集成示例

在你的登录页面添加按钮,点击后跳转授权页:

<!-- 编程指南登录按钮 -->
<button onclick="loginWithCodeGuide()">使用编程指南登录</button>

<script>
function loginWithCodeGuide() {
  const clientId = 'YOUR_CLIENT_ID';
  const redirectUri = encodeURIComponent('https://yoursite.com/callback');
  const state = Math.random().toString(36).substring(2);

  // 保存 state 到 sessionStorage,回调时验证
  sessionStorage.setItem('oauth_state', state);

  window.location.href =
    'https://code-guide.vip/oauth/consent' +
    '?client_id=' + clientId +
    '&redirect_uri=' + redirectUri +
    '&response_type=code' +
    '&scope=user_info' +
    '&state=' + state;
}
</script>

在回调页面处理授权结果:

// callback 页面
const params = new URLSearchParams(window.location.search);
const code = params.get('code');
const state = params.get('state');
const error = params.get('error');

// 验证 state 防止 CSRF
const savedState = sessionStorage.getItem('oauth_state');
if (state !== savedState) {
  alert('安全验证失败');
  return;
}

if (error) {
  // 用户拒绝授权
  console.log('授权被拒绝:', error);
  return;
}

if (code) {
  // 将 code 发送到你的后端换取 token
  fetch('/api/auth/code-guide/callback', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ code, state })
  })
  .then(res => res.json())
  .then(data => {
    // 登录成功,保存用户信息
    console.log('登录成功:', data);
  });
}

后端集成示例

以 Node.js(Express)为例:

const express = require('express');
const axios = require('axios');
const app = express();

const CLIENT_ID = 'your_client_id';
const CLIENT_SECRET = 'your_client_secret';
const REDIRECT_URI = 'https://yoursite.com/callback';
const API_BASE = 'https://api.code-guide.autogptai.club';

app.use(express.json());

// 处理回调
app.post('/api/auth/code-guide/callback', async (req, res) => {
  const { code } = req.body;

  try {
    // 第一步:用 code 换取 access_token
    const tokenRes = await axios.post(
      API_BASE + '/oauth/token',
      new URLSearchParams({
        grant_type: 'authorization_code',
        code,
        client_id: CLIENT_ID,
        client_secret: CLIENT_SECRET,
        redirect_uri: REDIRECT_URI
      }).toString(),
      { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
    );

    const { access_token, refresh_token } = tokenRes.data.data;

    // 第二步:用 access_token 获取用户信息
    const userRes = await axios.get(API_BASE + '/oauth/userinfo', {
      headers: { Authorization: 'Bearer ' + access_token }
    });

    const userInfo = userRes.data.data;

    // 第三步:在你的系统中查找或创建用户,生成登录态
    // ...

    res.json({
      success: true,
      user: userInfo,
      access_token,
      refresh_token
    });
  } catch (error) {
    console.error('OAuth 回调处理失败:', error);
    res.status(500).json({ success: false, message: '登录失败' });
  }
});

app.listen(3000);

常见问题

Q:code 过期了怎么办?

授权码(code)有效期为 5 分钟,且只能使用一次。过期后需要引导用户重新授权获取新的 code。

Q:access_token 过期了怎么办?

access_token 有效期为 2 小时。过期后使用 refresh_token 调用 /oauth/token/refresh 接口获取新的 access_token,无需用户重新授权。

Q:refresh_token 也过期了怎么办?

refresh_token 有效期为 30 天。过期后需要引导用户重新授权。

Q:redirect_uri 必须完全一致吗?

是的。授权请求中的 redirect_uri 必须与在开发者中心创建应用时填写的回调地址完全匹配,否则授权将失败。

Q:可以在前端直接用 code 换 token 吗?

不可以。 换取 token 需要使用 client_secret,该密钥不能暴露在前端代码中。请在你的服务端完成 code 换 token 的操作。

Q:如何保证安全性?

  • 始终使用 state 参数防止 CSRF 攻击
  • client_secret 只在服务端使用,不要暴露到前端
  • 使用 HTTPS 传输所有请求
  • 不再使用的令牌应主动撤销

更新日志

2026-03-20

  • 发布 OAuth 2.0 授权登录 v1.0
  • 支持 Authorization Code 授权码模式
  • 支持获取用户基本信息(uid、昵称、头像、简介)
  • 提供 access_token 刷新和撤销能力

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝