API_AUTH.md 7.0 KB

API Basic Auth 认证指南

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

安全原则

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

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

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

配置方式

1. 设置环境变量

在外部服务器的环境中设置以下变量:

# Basic Auth 用户名
export BYREAL_API_USERNAME=admin

# Basic Auth 密码
export BYREAL_API_PASSWORD=your_password_here

或者在 .env 文件中(不要提交到 Git):

BYREAL_API_USERNAME=admin
BYREAL_API_PASSWORD=your_password_here

代码示例

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}`

// 发送请求
const response = await fetch('http://your-server-ip/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('http://your-server-ip/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('http://your-server-ip/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(
    'http://your-server-ip/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('http://your-server-ip/api/my-lp', headers=headers)

curl 命令

# 从环境变量读取
curl -u "${BYREAL_API_USERNAME}:${BYREAL_API_PASSWORD}" \
  http://your-server-ip/api/my-lp

# 或者直接指定(不推荐,密码会出现在命令历史中)
curl -u "admin:your_password" \
  http://your-server-ip/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", "http://your-server-ip/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("http://your-server-ip/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. 使用环境变量:永远不要在代码中硬编码密码
  2. 使用 .gitignore:确保包含密码的 .env 文件不会被提交
  3. 使用密钥管理服务:生产环境推荐使用 AWS Secrets Manager、Azure Key Vault 等
  4. 定期轮换密码:定期更换 Basic Auth 密码
  5. 使用 HTTPS:生产环境必须使用 HTTPS(当前是 HTTP,仅用于开发/内网)
  6. 限制访问 IP:在 Nginx 中配置 allow/deny 限制允许访问的 IP
  7. 最小权限原则:只为需要的服务提供凭证

测试连接

使用 curl 测试 Basic Auth 是否配置正确:

# 测试(会提示输入密码)
curl -u admin http://your-server-ip/api/my-lp

# 或者从环境变量读取
curl -u "${BYREAL_API_USERNAME}:${BYREAL_API_PASSWORD}" \
  http://your-server-ip/api/my-lp

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


常见问题

Q: 如何获取 Basic Auth 凭证?

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

Q: 密码忘记了怎么办?

A: 在服务器上重新生成:

htpasswd ./htpasswd admin
# 输入新密码

然后重启 Docker 容器:

docker compose restart nginx

Q: 如何在生产环境使用 HTTPS?

A: 需要配置 SSL 证书,修改 nginx.conf 添加 SSL 配置,并更新 docker-compose.yml 映射 443 端口。


相关文件

  • nginx.conf - Nginx Basic Auth 配置
  • htpasswd - Basic Auth 密码文件(不提交到 Git)
  • docker-compose.yml - Docker 服务配置