# AcmeX v0.3.0 - 完整集成示例
## 完整证书申请流程
### 示例 1: HTTP-01 验证获取证书
```rust
use acmex::{
AcmeClient, AcmeConfig, ChallengeSolverRegistry, Http01Solver,
Contact, ChallengeType,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 初始化日志
tracing_subscriber::fmt::init();
// 1. 配置 ACME 客户端
let config = AcmeConfig::lets_encrypt_staging()
.with_contact(Contact::email("admin@example.com"))
.with_tos_agreed(true);
// 2. 创建客户端
let mut client = AcmeClient::new(config)?;
// 3. 注册账户
let account_id = client.register_account().await?;
println!("✅ 账户注册成功:{}", account_id);
// 4. 配置挑战求解器
let mut solver_registry = ChallengeSolverRegistry::new();
solver_registry.register(Http01Solver::new("0.0.0.0:80".parse()?));
// 5. 申请证书
let domains = vec!["example.com".to_string(), "www.example.com".to_string()];
let certificate = client.issue_certificate(domains, &mut solver_registry).await?;
println!("✅ 证书签发成功!");
println!(" 域名:{:?}", certificate.domains);
// 6. 保存证书和密钥
certificate.save_to_files("certificate.pem", "private_key.pem")?;
println!("✅ 证书已保存到文件");
Ok(())
}
```
### 示例 2: DNS-01 验证获取证书
```rust
use acmex::{
AcmeClient, AcmeConfig, ChallengeSolverRegistry, Dns01Solver,
Contact,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt::init();
// 配置
let config = AcmeConfig::lets_encrypt_staging()
.with_contact(Contact::email("admin@example.com"))
.with_tos_agreed(true);
let mut client = AcmeClient::new(config)?;
client.register_account().await?;
// 使用 DNS-01 验证 (支持通配符域名)
let mut solver_registry = ChallengeSolverRegistry::new();
solver_registry.register(Dns01Solver::with_mock("example.com".to_string()));
// 申请通配符证书
let domains = vec![
"example.com".to_string(),
"*.example.com".to_string(),
];
let certificate = client.issue_certificate(domains, &mut solver_registry).await?;
println!("✅ 通配符证书签发成功:{:?}", certificate.domains);
certificate.save_to_files("wildcard_cert.pem", "wildcard_key.pem")?;
Ok(())
}
```
### 示例 3: 手动订单流程 (低级 API)
```rust
use acmex::{
AccountManager, DirectoryManager, NonceManager, OrderManager,
KeyPair, Contact, NewOrderRequest, Identifier, CsrGenerator,
};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. 设置基础组件
let http_client = reqwest::Client::new();
let dir_url = "https://acme-staging-v02.api.letsencrypt.org/directory";
let dir_mgr = DirectoryManager::new(dir_url, http_client.clone());
let directory = dir_mgr.get().await?;
let key_pair = KeyPair::generate()?;
let nonce_mgr = NonceManager::new(&directory.new_nonce, http_client.clone());
// 2. 注册账户
let account_mgr = AccountManager::new(
&key_pair,
&nonce_mgr,
&dir_mgr,
&http_client,
)?;
let account = account_mgr.register(
vec![Contact::email("admin@example.com")],
true,
).await?;
println!("账户 ID: {}", account.id);
// 3. 创建订单
let order_mgr = OrderManager::new(
&account_mgr,
&dir_mgr,
&nonce_mgr,
&http_client,
account.id.clone(),
);
let domains = vec!["example.com".to_string()];
let identifiers: Vec<Identifier> = domains.iter().map(|d| Identifier::dns(d)).collect();
let order_req = NewOrderRequest {
identifiers,
not_before: None,
not_after: None,
};
let (order_url, mut order) = order_mgr.create_order(&order_req).await?;
println!("订单已创建:{}", order_url);
// 4. 处理授权和挑战
for auth_url in &order.authorizations {
let auth = order_mgr.get_authorization(auth_url).await?;
println!("处理授权:{:?}", auth.identifier);
// 获取 HTTP-01 挑战
if let Some(challenge) = auth.get_challenge("http-01") {
let key_auth = account_mgr.compute_key_authorization(&challenge.token)?;
// 在这里设置 HTTP 服务器提供 key_auth
// ...
// 告诉 ACME 服务器我们已准备好
order_mgr.respond_to_challenge(&challenge.url).await?;
}
}
// 5. 轮询订单直到 ready
order = order_mgr.poll_order(&order_url, 30, Duration::from_secs(2)).await?;
println!("订单状态:{}", order.status);
// 6. 生成 CSR 并完成订单
let csr_gen = CsrGenerator::new(domains.clone());
let (csr_der, private_key_pem) = csr_gen.generate()?;
order = order_mgr.finalize_order(&order.finalize, &csr_der).await?;
println!("订单已完成");
// 7. 等待证书签发
order = order_mgr.poll_order(&order_url, 30, Duration::from_secs(2)).await?;
if order.status == "valid" {
let cert_url = order.certificate.unwrap();
let cert_pem = order_mgr.download_certificate(&cert_url).await?;
std::fs::write("certificate.pem", cert_pem)?;
std::fs::write("private_key.pem", private_key_pem)?;
println!("✅ 证书已下载并保存");
}
Ok(())
}
```
### 示例 4: 使用现有密钥对
```rust
use acmex::{AcmeClient, AcmeConfig, KeyPair, Contact};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 从文件加载现有密钥
let key_pair = KeyPair::load_from_file("existing_account_key.pem")?;
let config = AcmeConfig::lets_encrypt()
.with_contact(Contact::email("admin@example.com"))
.with_tos_agreed(true);
// 使用现有密钥创建客户端
let client = AcmeClient::with_key_pair(config, key_pair);
// 继续正常流程...
Ok(())
}
```
### 示例 5: 自定义 DNS 提供商
```rust
use acmex::{DnsProvider, Dns01Solver};
use async_trait::async_trait;
use std::sync::Arc;
// 实现自定义 DNS 提供商 (例如 CloudFlare)
struct CloudFlareDnsProvider {
api_token: String,
zone_id: String,
}
#[async_trait]
impl DnsProvider for CloudFlareDnsProvider {
async fn create_txt_record(&self, domain: &str, value: &str) -> acmex::Result<String> {
// 调用 CloudFlare API 创建 TXT 记录
// let record_id = cloudflare_api_call(...).await?;
// Ok(record_id)
todo!("实现 CloudFlare API 调用")
}
async fn delete_txt_record(&self, domain: &str, record_id: &str) -> acmex::Result<()> {
// 调用 CloudFlare API 删除记录
// cloudflare_api_delete(...).await?;
// Ok(())
todo!("实现 CloudFlare API 调用")
}
async fn verify_record(&self, domain: &str, value: &str) -> acmex::Result<bool> {
// 查询 DNS 记录是否已传播
// let exists = query_dns(...).await?;
// Ok(exists)
todo!("实现 DNS 查询")
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let provider = Arc::new(CloudFlareDnsProvider {
api_token: "your-api-token".to_string(),
zone_id: "your-zone-id".to_string(),
});
let solver = Dns01Solver::new(provider, "example.com".to_string());
// 使用这个 solver 在 ChallengeSolverRegistry 中
let mut registry = ChallengeSolverRegistry::new();
registry.register(solver);
// ... 继续证书申请流程
Ok(())
}
```
### 示例 6: 批量域名证书申请
```rust
use acmex::{AcmeClient, AcmeConfig, ChallengeSolverRegistry, Http01Solver, Contact};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = AcmeConfig::lets_encrypt_staging()
.with_contact(Contact::email("admin@example.com"))
.with_tos_agreed(true);
let mut client = AcmeClient::new(config)?;
client.register_account().await?;
// 批量域名
let domain_groups = vec![
vec!["site1.com".to_string(), "www.site1.com".to_string()],
vec!["site2.com".to_string(), "www.site2.com".to_string()],
vec!["site3.com".to_string(), "www.site3.com".to_string()],
];
let mut solver_registry = ChallengeSolverRegistry::new();
solver_registry.register(Http01Solver::new("0.0.0.0:80".parse()?));
for (i, domains) in domain_groups.iter().enumerate() {
println!("处理证书组 {}: {:?}", i + 1, domains);
match client.issue_certificate(domains.clone(), &mut solver_registry).await {
Ok(cert) => {
let cert_file = format!("cert_{}.pem", i + 1);
let key_file = format!("key_{}.pem", i + 1);
cert.save_to_files(&cert_file, &key_file)?;
println!("✅ 证书 {} 已保存", i + 1);
}
Err(e) => {
eprintln!("❌ 证书 {} 申请失败:{}", i + 1, e);
}
}
}
Ok(())
}
```
### 示例 7: 验证证书内容
```rust
use acmex::{parse_certificate_chain, verify_certificate_domains};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 读取证书文件
let cert_pem = std::fs::read_to_string("certificate.pem")?;
// 解析证书链
let cert_chain = parse_certificate_chain(&cert_pem)?;
println!("证书链包含 {} 个证书", cert_chain.len());
// 验证域名
let expected_domains = vec!["example.com".to_string(), "www.example.com".to_string()];
let is_valid = verify_certificate_domains(&cert_chain[0], &expected_domains)?;
if is_valid {
println!("✅ 证书包含所有预期的域名");
} else {
println!("❌ 证书域名不匹配");
}
Ok(())
}
```
## 错误处理
### 示例 8: 完整的错误处理
```rust
use acmex::{AcmeClient, AcmeConfig, AcmeError, Contact};
#[tokio::main]
async fn main() {
let config = AcmeConfig::lets_encrypt_staging()
.with_contact(Contact::email("admin@example.com"))
.with_tos_agreed(true);
let mut client = match AcmeClient::new(config) {
Ok(c) => c,
Err(e) => {
eprintln!("创建客户端失败:{}", e);
return;
}
};
match client.register_account().await {
Ok(account_id) => println!("账户注册成功:{}", account_id),
Err(AcmeError::Account(msg)) => {
eprintln!("账户错误:{}", msg);
return;
}
Err(AcmeError::Transport(msg)) => {
eprintln!("网络错误:{}", msg);
return;
}
Err(e) => {
eprintln!("未知错误:{}", e);
return;
}
}
// ... 继续流程
}
```
## 配置选项
### ACME 服务器配置
```rust
// Let's Encrypt 生产环境
let config = AcmeConfig::lets_encrypt();
// Let's Encrypt 测试环境
let config = AcmeConfig::lets_encrypt_staging();
// 自定义 ACME 服务器
let config = AcmeConfig::new("https://custom-acme-server.com/directory");
// Google Trust Services (需要 feature flag)
#[cfg(feature = "google-ca")]
let config = AcmeConfig::new("https://dv.acme-v02.api.pki.goog/directory");
// ZeroSSL (需要 feature flag)
#[cfg(feature = "zerossl-ca")]
let config = AcmeConfig::new("https://acme.zerossl.com/v2/DV90/directory");
```
## 性能优化
### 重用客户端和密钥
```rust
use acmex::{AcmeClient, KeyPair};
use std::sync::Arc;
// 全局共享客户端
lazy_static::lazy_static! {
static ref ACME_CLIENT: Arc<AcmeClient> = {
let key_pair = KeyPair::load_from_file("account_key.pem")
.unwrap_or_else(|_| KeyPair::generate().unwrap());
let config = AcmeConfig::lets_encrypt()
.with_contact(Contact::email("admin@example.com"))
.with_tos_agreed(true);
Arc::new(AcmeClient::with_key_pair(config, key_pair))
};
}
// 在多个地方使用
async fn issue_cert_for_domain(domain: String) -> Result<(), Box<dyn std::error::Error>> {
let client = Arc::clone(&ACME_CLIENT);
// 使用客户端...
Ok(())
}
```
---
## 快速命令
```bash
# 运行完整示例
cargo run --example full_workflow
# 运行 HTTP-01 示例
cargo run --example http01_certificate
# 运行 DNS-01 示例
cargo run --example dns01_certificate
# 运行测试
cargo test --lib
# 构建发布版本
cargo build --release
```
---
**版本**: v0.3.0
**文档更新**: 2026-02-07