API_AUTH.md 8.0 KB

API Basic Auth 认证指南(Caddy 版本)

本文档说明外部服务器如何安全地调用本项目的 API 接口(已配置 Basic Auth)。

安全原则

⚠️ 重要:永远不要在代码中硬编码用户名和密码!

应该使用以下方式存储凭证:

  • 环境变量(推荐)
  • 密钥管理服务(如 AWS Secrets Manager、HashiCorp Vault)
  • 配置文件(不提交到 Git,使用 .gitignore

配置 Basic Auth

1. 生成密码哈希

Caddy 使用 bcrypt 哈希格式存储密码。使用以下命令生成:

# 使用 Docker 生成密码哈希(推荐)
docker run --rm caddy:2-alpine caddy hash-password --plaintext 'your_password'

# 示例输出:
# $2a$14$Z3Q7g2n8XQYuH9vJkLmNqOrStUvWxYzAbCdEfGhIjKlMnOpQrStUv

2. 配置环境变量

在服务器上的 .env 文件中添加:

# Basic Auth 配置
BASIC_AUTH_USER=admin
BASIC_AUTH_HASH=$2a$14$Z3Q7g2n8XQYuH9vJkLmNqOrStUvWxYzAbCdEfGhIjKlMnOpQrStUv

注意:将 BASIC_AUTH_HASH 替换为你实际生成的哈希值。


代码示例

Node.js / TypeScript

使用原生 fetch

// 从环境变量读取凭证
const username = process.env.BYREAL_API_USERNAME || ''
const password = process.env.BYREAL_API_PASSWORD || ''

// 生成 Basic Auth header
const credentials = Buffer.from(`${username}:${password}`).toString('base64')
const authHeader = `Basic ${credentials}`

// 发送请求(使用 HTTPS)
const response = await fetch('https://love.hdlife.me/api/my-lp', {
	method: 'GET',
	headers: {
		Authorization: authHeader,
		'Content-Type': 'application/json',
	},
})

const data = await response.json()

使用 axios

import axios from 'axios'

const username = process.env.BYREAL_API_USERNAME || ''
const password = process.env.BYREAL_API_PASSWORD || ''

const response = await axios.get('https://love.hdlife.me/api/my-lp', {
	auth: {
		username,
		password,
	},
	headers: {
		'Content-Type': 'application/json',
	},
})

const data = response.data

使用 ky

import ky from 'ky'

const username = process.env.BYREAL_API_USERNAME || ''
const password = process.env.BYREAL_API_PASSWORD || ''

const credentials = Buffer.from(`${username}:${password}`).toString('base64')

const response = await ky.get('https://love.hdlife.me/api/my-lp', {
	headers: {
		Authorization: `Basic ${credentials}`,
	},
})

const data = await response.json()

Python

使用 requests

import os
import requests
from requests.auth import HTTPBasicAuth

# 从环境变量读取
username = os.getenv('BYREAL_API_USERNAME', '')
password = os.getenv('BYREAL_API_PASSWORD', '')

# 方式 1: 使用 HTTPBasicAuth(推荐)
response = requests.get(
    'https://love.hdlife.me/api/my-lp',
    auth=HTTPBasicAuth(username, password),
    headers={'Content-Type': 'application/json'}
)

data = response.json()

# 方式 2: 手动设置 header
import base64
credentials = base64.b64encode(f'{username}:{password}'.encode()).decode()
headers = {
    'Authorization': f'Basic {credentials}',
    'Content-Type': 'application/json'
}
response = requests.get('https://love.hdlife.me/api/my-lp', headers=headers)

curl 命令

# 从环境变量读取
curl -u "${BYREAL_API_USERNAME}:${BYREAL_API_PASSWORD}" \
  https://love.hdlife.me/api/my-lp

# 或者直接指定(不推荐,密码会出现在命令历史中)
curl -u "admin:your_password" \
  https://love.hdlife.me/api/my-lp

Go

package main

import (
    "encoding/base64"
    "fmt"
    "io"
    "net/http"
    "os"
)

func main() {
    username := os.Getenv("BYREAL_API_USERNAME")
    password := os.Getenv("BYREAL_API_PASSWORD")

    credentials := base64.StdEncoding.EncodeToString([]byte(username + ":" + password))

    req, _ := http.NewRequest("GET", "https://love.hdlife.me/api/my-lp", nil)
    req.Header.Set("Authorization", "Basic "+credentials)
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}

Java

import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
import java.util.Base64;

public class ApiClient {
    public static void main(String[] args) {
        String username = System.getenv("BYREAL_API_USERNAME");
        String password = System.getenv("BYREAL_API_PASSWORD");

        String credentials = Base64.getEncoder().encodeToString(
            (username + ":" + password).getBytes()
        );

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://love.hdlife.me/api/my-lp"))
            .header("Authorization", "Basic " + credentials)
            .header("Content-Type", "application/json")
            .GET()
            .build();

        try {
            HttpResponse<String> response = client.send(request,
                HttpResponse.BodyHandlers.ofString());
            System.out.println(response.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Docker 环境配置

如果外部服务器也在 Docker 中运行,在 docker-compose.yml 中配置:

services:
  your-service:
    image: your-image
    environment:
      - BYREAL_API_USERNAME=${BYREAL_API_USERNAME}
      - BYREAL_API_PASSWORD=${BYREAL_API_PASSWORD}
    # 或者从 .env 文件读取
    env_file:
      - .env

部署步骤

1. 配置环境变量

在服务器上创建 .env 文件:

# Solana 配置
SOL_ENDPOINT=your_solana_endpoint
SOL_SECRET_KEY=your_secret_key

# Basic Auth 配置
BASIC_AUTH_USER=admin
BASIC_AUTH_HASH=$2a$14$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

2. 启动服务

docker compose down
docker compose up -d

3. 验证 HTTPS

访问 https://love.hdlife.me,应该会自动跳转到 HTTPS 并要求 Basic Auth。


安全最佳实践

  1. 使用环境变量:永远不要在代码中硬编码密码
  2. 使用 .gitignore:确保包含密码的 .env 文件不会被提交
  3. 使用密钥管理服务:生产环境推荐使用 AWS Secrets Manager、Azure Key Vault 等
  4. 定期轮换密码:定期更换 Basic Auth 密码
  5. 使用 HTTPS:Caddy 自动配置 HTTPS,无需额外操作
  6. 限制访问 IP:在服务器防火墙中限制允许的 IP
  7. 最小权限原则:只为需要的服务提供凭证

测试连接

使用 curl 测试 Basic Auth 和 HTTPS:

# 测试(会提示输入密码)
curl -u admin https://love.hdlife.me/api/my-lp

# 或者从环境变量读取
curl -u "${BYREAL_API_USERNAME}:${BYREAL_API_PASSWORD}" \
  https://love.hdlife.me/api/my-lp

如果返回 401 Unauthorized,说明凭证错误;如果返回 200 或其他业务状态码,说明认证成功。


常见问题

Q: 如何获取 Basic Auth 凭证?

A: 联系项目管理员获取用户名和密码。密码哈希存储在服务器的 .env 文件中。

Q: 密码忘记了怎么办?

A: 在服务器上重新生成哈希并更新 .env 文件:

# 生成新密码哈希
docker run --rm caddy:2-alpine caddy hash-password --plaintext 'new_password'

# 更新 .env 文件中的 BASIC_AUTH_HASH
# 然后重启服务
docker compose restart caddy

Q: 如何查看 Caddy 日志?

A:

# 查看 Caddy 容器日志
docker logs byreal-caddy

# 查看访问日志(如果在 Caddyfile 中配置了日志文件)
docker exec byreal-caddy cat /var/log/caddy/access.log

Q: HTTPS 证书如何续期?

A: Caddy 会自动管理 Let's Encrypt 证书的续期,无需手动操作。


相关文件

  • Caddyfile - Caddy HTTPS + Basic Auth 配置
  • docker-compose.yml - Docker 服务配置
  • .env - 环境变量配置(不提交到 Git)