热土用户开发者文档

欢迎使用热土用户开发者文档。本文档将帮助您了解如何集成热土用户系统到您的应用中,包括API调用、Token管理和软件认证流程。

注意: 所有API请求都需要通过我们提供的第三方API代理进行调用,代理地址为 https://appapi.rtstudio.top/api

env参数说明

登录页面支持env参数来指定授权模式:

参数值 说明 port参数含义 回调地址格式
app(默认) 桌面应用模式 本地端口号 http://127.0.0.1:端口
web Web应用模式 回调网址(不含http/https前缀) https://网址

使用示例:

概览

热土用户系统提供了一套完整的用户认证和授权机制,支持第三方应用通过Token进行身份验证和授权。主要功能包括:

API参考

第三方API提供了以下端点:

POST /verify-software-token

验证软件登录Token的有效性

请求参数:
参数名 类型 必填 描述
token string 软件登录Token
响应示例:
{"success": true, "data": {"id": 1, "name": "测试软件", "developer": "测试开发者"}}

POST /verify-access-token

验证用户授权Token的有效性

请求参数:
参数名 类型 必填 描述
token string 用户授权Token
响应示例:
{"success": true, "data": {"id": 1, "user_id": 1, "software_id": 1, "access_token": "...", "expires_at": "2027-03-22T12:00:00Z"}}

POST /get-user-by-token

根据用户授权Token获取用户信息

请求参数:
参数名 类型 必填 描述
token string 用户授权Token
响应示例:
{"success": true, "data": {"id": 1, "uuid": "...", "username": "testuser", "email": "test@example.com", "email_verified": true, "is_beta_user": false}}

POST /data-segments

创建数据段

重要限制:数据段功能仅限已验证软件使用,未验证软件无法使用此功能。每个用户最多可创建10个数据段。
请求参数:
参数名 类型 必填 描述
email string 用户邮箱
token string 用户授权Token
name string 数据段名称
content string 数据段内容
响应示例:
{"success": true, "message": "数据段创建成功", "data": {"id": 1, "name": "user_settings", "content": "{\"theme\": \"dark\", \"language\": \"zh-CN\"}"}}

PUT /data-segments

修改数据段

重要限制:数据段功能仅限已验证软件使用,未验证软件无法使用此功能。
请求参数:
参数名 类型 必填 描述
email string 用户邮箱
token string 用户授权Token
name string 数据段名称
content string 数据段内容
响应示例:
{"success": true, "message": "数据段更新成功", "data": {"name": "user_settings", "content": "{\"theme\": \"light\", \"language\": \"zh-CN\"}"}}

DELETE /data-segments

删除数据段

重要限制:数据段功能仅限已验证软件使用,未验证软件无法使用此功能。
请求参数:
参数名 类型 必填 描述
email string 用户邮箱
token string 用户授权Token
name string 数据段名称
响应示例:
{"success": true, "message": "数据段删除成功"}

POST /data-segments/read

读取数据段

重要限制:数据段功能仅限已验证软件使用,未验证软件无法使用此功能。
请求参数:
参数名 类型 必填 描述
email string 用户邮箱
token string 用户授权Token
name string 数据段名称
响应示例:
{"success": true, "message": "数据段读取成功", "data": {"id": 1, "name": "user_settings", "content": "{\"theme\": \"dark\", \"language\": \"zh-CN\"}", "created_at": "2026-03-22T12:00:00Z", "updated_at": "2026-03-22T12:00:00Z"}}

Token授权流程

热土用户系统支持两种类型的软件授权:

1. 已认证软件授权流程

已认证软件是指通过热土工作室审核的软件,具有更高的安全性和可信度。

  1. 软件开发者向热土工作室申请软件认证,获取软件Token
  2. 软件启动时,生成安全的state参数
  3. 软件构造登录链接并打开浏览器:https://apilogin.rtstudio.top/?port=${本地端口}&type=token&v=${软件Token}&state=${state}&env=app
  4. 用户在浏览器中确认登录,输入账号密码
  5. 服务器验证用户凭据和软件Token
  6. 服务器生成用户授权Token并返回给软件
  7. 软件使用授权Token调用API获取用户信息

2. 未认证软件授权流程

未认证软件是指尚未通过热土工作室审核的软件,用户登录时会收到安全警告。

  1. 软件启动时,生成安全的state参数
  2. 软件构造登录链接并打开浏览器:https://apilogin.rtstudio.top/?port=${本地端口}&type=name&v=${软件名称}&state=${state}&env=app
  3. 用户在浏览器中确认登录,输入账号密码
  4. 服务器验证用户凭据
  5. 服务器生成用户授权Token并返回给软件
  6. 软件使用授权Token调用API获取用户信息

3. Web应用授权流程

对于Web应用,可以使用web模式进行授权,此时port参数为回调网址。

  1. Web应用生成安全的state参数
  2. 构造登录链接并跳转:https://apilogin.rtstudio.top/?port=${回调网址}&type=token&v=${软件Token}&state=${state}&env=web
  3. 用户在登录页面确认登录,输入账号密码
  4. 服务器验证用户凭据和软件Token
  5. 服务器生成用户授权Token并重定向到回调网址
  6. Web应用从URL参数中获取授权Token

4. 完整的登录流程实现(Go语言)

以下是实现完整登录流程的详细步骤(基于login_mod文件夹的Go语言代码):

步骤1:启动本地Web服务器

软件需要在本地启动一个Web服务器,用于接收登录结果回调。

// main.go
package main

import (
    "bytes"
    "crypto/rand"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net"
    "net/http"
    "os/exec"
    "runtime"
    "time"
)

// 配置常量
const apiBaseURL = "https://appapi.rtstudio.top"

// 命令行参数
var (
    loginType string // token 或 name
    value     string // 软件token或软件名称
)

// 验证响应结构
type verifyResponse struct {
    Success bool   `json:"success"`
    Data    any    `json:"data"`
    Message string `json:"message"`
}

func main() {
    // 启动登录流程
    token, err := startLoginFlow(loginType, value)
    if err != nil {
        log.Fatalf("登录失败: %v", err)
    }

    // 验证token有效性
    if err := verifyToken(token); err != nil {
        log.Fatalf("token验证失败: %v", err)
    }

    fmt.Print(token)
}

步骤2:构造登录链接并打开浏览器

软件需要构造登录链接并打开浏览器,引导用户登录。

// startLoginFlow 启动完整的登录流程
func startLoginFlow(loginType, value string) (string, error) {
    // 1. 生成state参数 (16字节随机数,防CSRF)
    state, err := generateState()
    if err != nil {
        return "", fmt.Errorf("生成state失败: %v", err)
    }

    // 2. 寻找可用端口并启动本地服务器
    port, err := findAvailablePort()
    if err != nil {
        return "", fmt.Errorf("无法找到可用端口: %v", err)
    }

    // 创建channel用于接收token或错误
    tokenChan := make(chan string, 1)
    errChan := make(chan error, 1)

    // 启动HTTP服务器
    server := &http.Server{
        Addr:         fmt.Sprintf(":%d", port),
        ReadTimeout:  10 * time.Second,
        WriteTimeout: 10 * time.Second,
    }

    // 注册路由处理器
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        if r.Method != http.MethodGet {
            http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
            return
        }

        query := r.URL.Query()
        callbackType := query.Get("type")
        callbackValue := query.Get("v")
        callbackState := query.Get("state")

        if callbackType == "success" {
            // 验证state参数,防止CSRF攻击
            if callbackState != state {
                errChan <- fmt.Errorf("state参数验证失败")
                http.Error(w, "state验证失败", http.StatusBadRequest)
                return
            }
            tokenChan <- callbackValue
            w.Header().Set("Content-Type", "text/html; charset=utf-8")
            w.WriteHeader(http.StatusOK)
            w.Write([]byte(`登录成功

✅ 登录完成

请关闭此窗口

`)) go func() { time.Sleep(500 * time.Millisecond) server.Close() }() } else if callbackType == "error" { errChan <- fmt.Errorf("登录失败: %s", callbackValue) http.Error(w, "登录失败", http.StatusBadRequest) go func() { time.Sleep(500 * time.Millisecond) server.Close() }() } else { http.Error(w, "无效的回调类型", http.StatusBadRequest) } }) // 在goroutine中启动服务器 go func() { if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { errChan <- fmt.Errorf("HTTP服务器错误: %v", err) } }() // 等待服务器启动 time.Sleep(100 * time.Millisecond) // 3. 构造登录URL并打开浏览器 loginURL := fmt.Sprintf("https://apilogin.rtstudio.top/?port=%d&type=%s&v=%s&state=%s&env=app", port, loginType, value, state) log.Printf("构造的登录URL: %s", loginURL) if err := openBrowser(loginURL); err != nil { return "", fmt.Errorf("打开浏览器失败: %v", err) } log.Printf("已打开浏览器,请登录") // 等待登录结果 select { case token := <-tokenChan: return token, nil case err := <-errChan: return "", err case <-time.After(5 * time.Minute): server.Close() return "", fmt.Errorf("登录超时(5分钟)") } } // generateState 生成16字节随机数作为state参数 func generateState() (string, error) { bytes := make([]byte, 16) if _, err := rand.Read(bytes); err != nil { return "", err } return hex.EncodeToString(bytes), nil } // findAvailablePort 寻找一个可用的TCP端口 func findAvailablePort() (int, error) { listener, err := net.Listen("tcp", ":0") if err != nil { return 0, err } defer listener.Close() return listener.Addr().(*net.TCPAddr).Port, nil } // openBrowser 打开系统默认浏览器 func openBrowser(url string) error { switch runtime.GOOS { case "windows": return exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start() case "darwin": return exec.Command("open", url).Start() default: return exec.Command("xdg-open", url).Start() } }

步骤3:使用获取到的token调用API

登录成功后,软件可以使用获取到的token调用API获取用户信息。

// verifyToken 验证token有效性
func verifyToken(token string) error {
    reqBody := map[string]string{"token": token}
    jsonBody, err := json.Marshal(reqBody)
    if err != nil {
        return err
    }

    resp, err := http.Post(apiBaseURL+"/verify-access-token", "application/json", bytes.NewBuffer(jsonBody))
    if err != nil {
        return fmt.Errorf("API请求失败: %v", err)
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return err
    }

    var result verifyResponse
    if err := json.Unmarshal(body, &result); err != nil {
        return err
    }

    if !result.Success {
        return fmt.Errorf("token无效: %s", result.Message)
    }

    return nil
}

// getUserByToken 根据token获取用户信息
func getUserByToken(token string) (*verifyResponse, error) {
    reqBody := map[string]string{"token": token}
    jsonBody, err := json.Marshal(reqBody)
    if err != nil {
        return nil, err
    }

    resp, err := http.Post(apiBaseURL+"/get-user-by-token", "application/json", bytes.NewBuffer(jsonBody))
    if err != nil {
        return nil, fmt.Errorf("API请求失败: %v", err)
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    var result verifyResponse
    if err := json.Unmarshal(body, &result); err != nil {
        return nil, err
    }

    return &result, nil
}

完整示例代码

// main.go
// 使用方法: go run main.go -type token -v your_software_token
// 或: go run main.go -type name -v your_software_name
package main

import (
    "bytes"
    "crypto/rand"
    "encoding/hex"
    "encoding/json"
    "flag"
    "fmt"
    "io"
    "log"
    "net"
    "net/http"
    "os/exec"
    "runtime"
    "time"
)

const apiBaseURL = "https://appapi.rtstudio.top"

var loginType string
var value     string

type verifyResponse struct {
    Success bool   `json:"success"`
    Data    any    `json:"data"`
    Message string `json:"message"`
}

func main() {
    flag.StringVar(&loginType, "type", "", "登录类型: token (已认证软件) 或 name (未认证软件)")
    flag.StringVar(&value, "v", "", "软件token (type=token时) 或软件名称 (type=name时)")
    flag.Parse()

    if loginType != "token" && loginType != "name" {
        log.Fatal("错误: -type 必须是 'token' 或 'name'")
    }
    if value == "" {
        log.Fatal("错误: -v 参数不能为空")
    }

    token, err := startLoginFlow(loginType, value)
    if err != nil {
        log.Fatalf("登录失败: %v", err)
    }

    if err := verifyToken(token); err != nil {
        log.Fatalf("token验证失败: %v", err)
    }

    // 获取用户信息
    userResult, err := getUserByToken(token)
    if err != nil {
        log.Fatalf("获取用户信息失败: %v", err)
    }
    
    if userResult.Success {
        log.Printf("登录成功,用户信息: %+v", userResult.Data)
    }

    fmt.Print(token)
}

func startLoginFlow(loginType, value string) (string, error) {
    state, err := generateState()
    if err != nil {
        return "", fmt.Errorf("生成state失败: %v", err)
    }

    port, err := findAvailablePort()
    if err != nil {
        return "", fmt.Errorf("无法找到可用端口: %v", err)
    }

    tokenChan := make(chan string, 1)
    errChan := make(chan error, 1)

    server := &http.Server{
        Addr:         fmt.Sprintf(":%d", port),
        ReadTimeout:  10 * time.Second,
        WriteTimeout: 10 * time.Second,
    }

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        if r.Method != http.MethodGet {
            http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
            return
        }

        query := r.URL.Query()
        callbackType := query.Get("type")
        callbackValue := query.Get("v")
        callbackState := query.Get("state")

        if callbackType == "success" {
            if callbackState != state {
                errChan <- fmt.Errorf("state参数验证失败")
                http.Error(w, "state验证失败", http.StatusBadRequest)
                return
            }
            tokenChan <- callbackValue
            w.Header().Set("Content-Type", "text/html; charset=utf-8")
            w.WriteHeader(http.StatusOK)
            w.Write([]byte(`登录成功

✅ 登录完成

请关闭此窗口

`)) go func() { time.Sleep(500 * time.Millisecond) server.Close() }() } else if callbackType == "error" { errChan <- fmt.Errorf("登录失败: %s", callbackValue) http.Error(w, "登录失败", http.StatusBadRequest) go func() { time.Sleep(500 * time.Millisecond) server.Close() }() } else { http.Error(w, "无效的回调类型", http.StatusBadRequest) } }) go func() { if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { errChan <- fmt.Errorf("HTTP服务器错误: %v", err) } }() time.Sleep(100 * time.Millisecond) loginURL := fmt.Sprintf("https://apilogin.rtstudio.top/?port=%d&type=%s&v=%s&state=%s&env=app", port, loginType, value, state) log.Printf("构造的登录URL: %s", loginURL) if err := openBrowser(loginURL); err != nil { return "", fmt.Errorf("打开浏览器失败: %v", err) } log.Printf("已打开浏览器,请登录") select { case token := <-tokenChan: return token, nil case err := <-errChan: return "", err case <-time.After(5 * time.Minute): server.Close() return "", fmt.Errorf("登录超时(5分钟)") } } func generateState() (string, error) { bytes := make([]byte, 16) if _, err := rand.Read(bytes); err != nil { return "", err } return hex.EncodeToString(bytes), nil } func findAvailablePort() (int, error) { listener, err := net.Listen("tcp", ":0") if err != nil { return 0, err } defer listener.Close() return listener.Addr().(*net.TCPAddr).Port, nil } func openBrowser(url string) error { switch runtime.GOOS { case "windows": return exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start() case "darwin": return exec.Command("open", url).Start() default: return exec.Command("xdg-open", url).Start() } } func verifyToken(token string) error { reqBody := map[string]string{"token": token} jsonBody, err := json.Marshal(reqBody) if err != nil { return err } resp, err := http.Post(apiBaseURL+"/verify-access-token", "application/json", bytes.NewBuffer(jsonBody)) if err != nil { return fmt.Errorf("API请求失败: %v", err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return err } var result verifyResponse if err := json.Unmarshal(body, &result); err != nil { return err } if !result.Success { return fmt.Errorf("token无效: %s", result.Message) } return nil } func getUserByToken(token string) (*verifyResponse, error) { reqBody := map[string]string{"token": token} jsonBody, err := json.Marshal(reqBody) if err != nil { return nil, err } resp, err := http.Post(apiBaseURL+"/get-user-by-token", "application/json", bytes.NewBuffer(jsonBody)) if err != nil { return nil, fmt.Errorf("API请求失败: %v", err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return nil, err } var result verifyResponse if err := json.Unmarshal(body, &result); err != nil { return nil, err } return &result, nil }

软件认证流程

如果您希望您的软件成为已认证软件,需要按照以下流程申请:

已验证软件 vs 未验证软件

已验证软件:

  • 通过热土工作室的安全审核
  • 拥有唯一的软件Token
  • 可以使用数据段功能(最多10个数据段)
  • 用户登录时显示软件名称和开发者信息
  • 在用户仪表盘中显示为已授权应用

未验证软件:

  • 未通过热土工作室的安全审核
  • 使用软件名称进行登录
  • 无法使用数据段功能
  • 用户登录时会显示风险警告和免责声明
  • 在用户仪表盘中显示为未授权应用

申请已验证软件

  1. 准备以下材料:
    • 软件名称
    • 软件开发者信息
    • 软件功能描述
    • 软件截图
    • 软件下载链接(如果有)
  2. 发送邮件到 miles@rtstu.com,主题为「软件认证申请」
  3. 等待热土工作室审核(通常1-3个工作日)
  4. 审核通过后,您将收到包含软件Token的邮件
注意: 软件认证申请需要确保您的软件符合热土用户系统的安全规范,不包含恶意代码或行为。

示例代码

以下是使用第三方API的示例代码:

验证软件Token

// verifySoftwareToken 验证软件Token
func verifySoftwareToken(token string) (*verifyResponse, error) {
    reqBody := map[string]string{"token": token}
    jsonBody, err := json.Marshal(reqBody)
    if err != nil {
        return nil, err
    }

    resp, err := http.Post(apiBaseURL+"/verify-software-token", "application/json", bytes.NewBuffer(jsonBody))
    if err != nil {
        return nil, fmt.Errorf("API请求失败: %v", err)
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    var result verifyResponse
    if err := json.Unmarshal(body, &result); err != nil {
        return nil, err
    }

    return &result, nil
}

// 使用示例
func main() {
    result, err := verifySoftwareToken("your_software_token")
    if err != nil {
        log.Printf("验证失败: %v", err)
        return
    }
    if result.Success {
        log.Printf("软件验证成功: %+v", result.Data)
    } else {
        log.Printf("软件验证失败: %s", result.Message)
    }
}

验证用户授权Token

// verifyAccessToken 验证用户授权Token
func verifyAccessToken(token string) (*verifyResponse, error) {
    reqBody := map[string]string{"token": token}
    jsonBody, err := json.Marshal(reqBody)
    if err != nil {
        return nil, err
    }

    resp, err := http.Post(apiBaseURL+"/verify-access-token", "application/json", bytes.NewBuffer(jsonBody))
    if err != nil {
        return nil, fmt.Errorf("API请求失败: %v", err)
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    var result verifyResponse
    if err := json.Unmarshal(body, &result); err != nil {
        return nil, err
    }

    return &result, nil
}

// 使用示例
func main() {
    result, err := verifyAccessToken("user_access_token")
    if err != nil {
        log.Printf("验证失败: %v", err)
        return
    }
    if result.Success {
        log.Printf("Token验证成功: %+v", result.Data)
    } else {
        log.Printf("Token验证失败: %s", result.Message)
    }
}

获取用户信息

// getUserByToken 根据Token获取用户信息
func getUserByToken(token string) (*verifyResponse, error) {
    reqBody := map[string]string{"token": token}
    jsonBody, err := json.Marshal(reqBody)
    if err != nil {
        return nil, err
    }

    resp, err := http.Post(apiBaseURL+"/get-user-by-token", "application/json", bytes.NewBuffer(jsonBody))
    if err != nil {
        return nil, fmt.Errorf("API请求失败: %v", err)
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    var result verifyResponse
    if err := json.Unmarshal(body, &result); err != nil {
        return nil, err
    }

    return &result, nil
}

// 使用示例
func main() {
    result, err := getUserByToken("user_access_token")
    if err != nil {
        log.Printf("获取失败: %v", err)
        return
    }
    if result.Success {
        log.Printf("用户信息: %+v", result.Data)
    } else {
        log.Printf("获取失败: %s", result.Message)
    }
}

创建数据段

// createDataSegment 创建数据段
func createDataSegment(email, token, name, content string) (*verifyResponse, error) {
    reqBody := map[string]string{
        "email":   email,
        "token":   token,
        "name":    name,
        "content": content,
    }
    jsonBody, err := json.Marshal(reqBody)
    if err != nil {
        return nil, err
    }

    resp, err := http.Post(apiBaseURL+"/data-segments", "application/json", bytes.NewBuffer(jsonBody))
    if err != nil {
        return nil, fmt.Errorf("API请求失败: %v", err)
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    var result verifyResponse
    if err := json.Unmarshal(body, &result); err != nil {
        return nil, err
    }

    return &result, nil
}

// 使用示例
func main() {
    result, err := createDataSegment(
        "user@example.com",
        "user_access_token",
        "user_settings",
        `{"theme": "dark", "language": "zh-CN"}`,
    )
    if err != nil {
        log.Printf("创建数据段失败: %v", err)
        return
    }
    if result.Success {
        log.Printf("数据段创建成功: %+v", result.Data)
    } else {
        log.Printf("创建失败: %s", result.Message)
    }
}

修改数据段

// updateDataSegment 修改数据段
func updateDataSegment(email, token, name, content string) (*verifyResponse, error) {
    reqBody := map[string]string{
        "email":   email,
        "token":   token,
        "name":    name,
        "content": content,
    }
    jsonBody, err := json.Marshal(reqBody)
    if err != nil {
        return nil, err
    }

    req, err := http.NewRequest("PUT", apiBaseURL+"/data-segments", bytes.NewBuffer(jsonBody))
    if err != nil {
        return nil, err
    }
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return nil, fmt.Errorf("API请求失败: %v", err)
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    var result verifyResponse
    if err := json.Unmarshal(body, &result); err != nil {
        return nil, err
    }

    return &result, nil
}

// 使用示例
func main() {
    result, err := updateDataSegment(
        "user@example.com",
        "user_access_token",
        "user_settings",
        `{"theme": "light", "language": "zh-CN"}`,
    )
    if err != nil {
        log.Printf("修改数据段失败: %v", err)
        return
    }
    if result.Success {
        log.Printf("数据段更新成功: %+v", result.Data)
    } else {
        log.Printf("更新失败: %s", result.Message)
    }
}

删除数据段

// deleteDataSegment 删除数据段
func deleteDataSegment(email, token, name string) (*verifyResponse, error) {
    reqBody := map[string]string{
        "email": email,
        "token": token,
        "name":  name,
    }
    jsonBody, err := json.Marshal(reqBody)
    if err != nil {
        return nil, err
    }

    req, err := http.NewRequest("DELETE", apiBaseURL+"/data-segments", bytes.NewBuffer(jsonBody))
    if err != nil {
        return nil, err
    }
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return nil, fmt.Errorf("API请求失败: %v", err)
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    var result verifyResponse
    if err := json.Unmarshal(body, &result); err != nil {
        return nil, err
    }

    return &result, nil
}

// 使用示例
func main() {
    result, err := deleteDataSegment(
        "user@example.com",
        "user_access_token",
        "user_settings",
    )
    if err != nil {
        log.Printf("删除数据段失败: %v", err)
        return
    }
    if result.Success {
        log.Printf("数据段删除成功")
    } else {
        log.Printf("删除失败: %s", result.Message)
    }
}

读取数据段

// readDataSegment 读取数据段
func readDataSegment(email, token, name string) (*verifyResponse, error) {
    reqBody := map[string]string{
        "email": email,
        "token": token,
        "name":  name,
    }
    jsonBody, err := json.Marshal(reqBody)
    if err != nil {
        return nil, err
    }

    resp, err := http.Post(apiBaseURL+"/data-segments/read", "application/json", bytes.NewBuffer(jsonBody))
    if err != nil {
        return nil, fmt.Errorf("API请求失败: %v", err)
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    var result verifyResponse
    if err := json.Unmarshal(body, &result); err != nil {
        return nil, err
    }

    return &result, nil
}

// 使用示例
func main() {
    result, err := readDataSegment(
        "user@example.com",
        "user_access_token",
        "user_settings",
    )
    if err != nil {
        log.Printf("读取数据段失败: %v", err)
        return
    }
    if result.Success {
        log.Printf("数据段读取成功: %+v", result.Data)
    } else {
        log.Printf("读取失败: %s", result.Message)
    }
}

常见问题

Q: 软件Token和用户授权Token有什么区别?

A: 软件Token是用于标识软件身份的令牌,由热土工作室颁发给已认证的软件;用户授权Token是用户登录后生成的令牌,用于访问用户信息。

Q: 如何安全地存储软件Token?

A: 软件Token应该安全存储在软件中,避免硬编码在源代码中,建议使用环境变量或加密存储。

Q: 用户授权Token的有效期是多久?

A: 用户授权Token的有效期为1年,过期后需要重新登录。

Q: 如何申请软件认证?

A: 请发送邮件到 miles@rtstu.com 申请软件认证,包含软件名称、开发者信息、功能描述等。

Q: 第三方API的速率限制是多少?

A: 目前第三方API没有速率限制,但建议合理使用,避免过度请求。

Q: 数据段是什么?有什么用途?

A: 数据段是用户存储在热土用户系统中的数据,软件可以通过API创建、修改和删除这些数据段。数据段可以用于存储用户的设置、偏好、游戏存档等信息。

Q: 数据段的大小限制是多少?

A: 目前数据段的内容大小限制为1MB,超过这个限制的请求会被拒绝。

Q: 数据段的最大数量是多少?

A: 目前一个已授权的Token下可以存最多10个数据段。

Q: 数据段功能有哪些限制?

A: 数据段功能仅限已验证软件使用,未验证软件无法使用数据段功能。已验证软件需要通过热土工作室的认证,并拥有有效的软件Token。

Q: 数据段的访问权限如何控制?

A: 数据段的访问需要提供用户邮箱和有效的访问Token,确保只有授权的软件能够访问用户的数据。

Q: 如何安全地存储用户的敏感信息?

A: 数据段中不建议存储密码、银行卡号等敏感信息。如果需要存储敏感信息,建议在客户端进行加密后再存储。