凭证管理
本示例演示如何使用 NuGet Config Parser 库管理 NuGet 包源的认证凭证,包括用户名/密码、API密钥和令牌认证。
概述
凭证管理包括:
- 为私有包源添加用户名/密码认证
- 管理API密钥和访问令牌
- 处理不同的认证方式
- 安全存储和检索凭证
- 批量凭证配置
示例 1: 基本凭证管理
为包源添加和管理基本认证:
go
package main
import (
"fmt"
"log"
"github.com/scagogogo/nuget-config-parser/pkg/nuget"
)
func main() {
api := nuget.NewAPI()
config := api.CreateDefaultConfig()
fmt.Println("=== 基本凭证管理 ===")
// 添加需要认证的包源
privateSources := []struct {
name string
url string
username string
password string
}{
{"company-internal", "https://nuget.company.com/v3/index.json", "employee", "company_pass123"},
{"azure-artifacts", "https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json", "myuser", "pat_token_here"},
{"private-feed", "https://private.nuget.com/api/v3/index.json", "user@company.com", "secure_password"},
}
fmt.Println("添加私有包源和凭证...")
for _, source := range privateSources {
// 添加包源
api.AddPackageSource(config, source.name, source.url, "3")
fmt.Printf("✅ 添加包源: %s\n", source.name)
// 添加凭证
api.AddCredential(config, source.name, source.username, source.password)
fmt.Printf("🔐 添加凭证: %s (用户: %s)\n", source.name, source.username)
}
// 添加公共源(无需凭证)
api.AddPackageSource(config, "nuget.org", "https://api.nuget.org/v3/index.json", "3")
fmt.Println("✅ 添加公共源: nuget.org")
// 显示配置摘要
fmt.Printf("\n=== 配置摘要 ===\n")
fmt.Printf("总包源数: %d\n", len(config.PackageSources.Add))
// 显示所有源及其认证状态
for _, source := range config.PackageSources.Add {
hasCredentials := "❌ 无认证"
if config.PackageSourceCredentials != nil {
if _, exists := config.PackageSourceCredentials.Sources[source.Key]; exists {
hasCredentials = "✅ 已配置认证"
}
}
fmt.Printf("- %s: %s [%s]\n", source.Key, source.Value, hasCredentials)
}
// 验证凭证
fmt.Println("\n=== 凭证验证 ===")
for _, source := range privateSources {
credential := api.GetCredential(config, source.name)
if credential != nil {
fmt.Printf("✅ %s: 用户名=%s, 密码已设置\n", source.name, credential.Username.Value)
} else {
fmt.Printf("❌ %s: 未找到凭证\n", source.name)
}
}
// 保存配置
err := api.SaveConfig(config, "CredentialsDemo.Config")
if err != nil {
log.Fatalf("保存配置失败: %v", err)
}
fmt.Println("\n配置已保存到 CredentialsDemo.Config")
fmt.Println("⚠️ 注意: 生产环境中应使用更安全的凭证存储方式")
}
示例 2: 高级凭证配置
处理复杂的认证场景:
go
package main
import (
"fmt"
"log"
"os"
"strings"
"github.com/scagogogo/nuget-config-parser/pkg/nuget"
)
func main() {
api := nuget.NewAPI()
config := api.CreateDefaultConfig()
fmt.Println("=== 高级凭证配置 ===")
// 从环境变量获取凭证
credentialsFromEnv := getCredentialsFromEnvironment()
// 配置不同类型的认证
configureAuthentication(api, config, credentialsFromEnv)
// 演示凭证更新
demonstrateCredentialUpdates(api, config)
// 演示凭证移除
demonstrateCredentialRemoval(api, config)
// 保存最终配置
err := api.SaveConfig(config, "AdvancedCredentials.Config")
if err != nil {
log.Fatalf("保存配置失败: %v", err)
}
fmt.Println("\n高级凭证配置完成")
}
type CredentialConfig struct {
SourceName string
URL string
AuthType string // "basic", "token", "apikey"
Username string
Password string
Token string
APIKey string
}
func getCredentialsFromEnvironment() []CredentialConfig {
fmt.Println("从环境变量获取凭证...")
credentials := []CredentialConfig{
{
SourceName: "company-prod",
URL: "https://prod.company.com/nuget",
AuthType: "basic",
Username: getEnvOrDefault("COMPANY_NUGET_USER", "default_user"),
Password: getEnvOrDefault("COMPANY_NUGET_PASS", "default_pass"),
},
{
SourceName: "azure-devops",
URL: "https://pkgs.dev.azure.com/myorg/_packaging/main/nuget/v3/index.json",
AuthType: "token",
Username: "PAT", // Personal Access Token 通常使用 PAT 作为用户名
Token: getEnvOrDefault("AZURE_DEVOPS_PAT", "default_pat_token"),
},
{
SourceName: "github-packages",
URL: "https://nuget.pkg.github.com/myorg/index.json",
AuthType: "token",
Username: getEnvOrDefault("GITHUB_USERNAME", "github_user"),
Token: getEnvOrDefault("GITHUB_TOKEN", "github_token"),
},
{
SourceName: "myget-feed",
URL: "https://www.myget.org/F/myfeed/api/v3/index.json",
AuthType: "apikey",
APIKey: getEnvOrDefault("MYGET_API_KEY", "myget_api_key"),
},
}
for _, cred := range credentials {
fmt.Printf("✅ 环境凭证: %s (%s)\n", cred.SourceName, cred.AuthType)
}
return credentials
}
func configureAuthentication(api *nuget.API, config *types.NuGetConfig, credentials []CredentialConfig) {
fmt.Println("\n配置不同类型的认证...")
for _, cred := range credentials {
// 添加包源
api.AddPackageSource(config, cred.SourceName, cred.URL, "3")
fmt.Printf("📦 添加源: %s\n", cred.SourceName)
// 根据认证类型配置凭证
switch cred.AuthType {
case "basic":
api.AddCredential(config, cred.SourceName, cred.Username, cred.Password)
fmt.Printf("🔐 基本认证: %s (用户: %s)\n", cred.SourceName, cred.Username)
case "token":
// 对于令牌认证,通常将令牌作为密码
username := cred.Username
if username == "" {
username = "token" // 默认用户名
}
api.AddCredential(config, cred.SourceName, username, cred.Token)
fmt.Printf("🎫 令牌认证: %s (用户: %s)\n", cred.SourceName, username)
case "apikey":
// API密钥通常作为密码,用户名可以是任意值
api.AddCredential(config, cred.SourceName, "apikey", cred.APIKey)
fmt.Printf("🔑 API密钥认证: %s\n", cred.SourceName)
default:
fmt.Printf("⚠️ 未知认证类型: %s for %s\n", cred.AuthType, cred.SourceName)
}
}
}
func demonstrateCredentialUpdates(api *nuget.API, config *types.NuGetConfig) {
fmt.Println("\n=== 凭证更新演示 ===")
// 模拟凭证轮换场景
updates := []struct {
sourceName string
newUsername string
newPassword string
reason string
}{
{"company-prod", "new_user", "new_secure_pass", "定期密码轮换"},
{"azure-devops", "PAT", "new_pat_token_2024", "PAT令牌更新"},
{"github-packages", "updated_user", "new_github_token", "GitHub令牌刷新"},
}
for _, update := range updates {
fmt.Printf("🔄 更新凭证: %s (%s)\n", update.sourceName, update.reason)
// 更新凭证(实际上是重新添加)
api.AddCredential(config, update.sourceName, update.newUsername, update.newPassword)
// 验证更新
credential := api.GetCredential(config, update.sourceName)
if credential != nil && credential.Username.Value == update.newUsername {
fmt.Printf("✅ 凭证更新成功: %s\n", update.sourceName)
} else {
fmt.Printf("❌ 凭证更新失败: %s\n", update.sourceName)
}
}
}
func demonstrateCredentialRemoval(api *nuget.API, config *types.NuGetConfig) {
fmt.Println("\n=== 凭证移除演示 ===")
// 移除不再需要的凭证
sourcesToRemove := []string{"myget-feed"}
for _, sourceName := range sourcesToRemove {
fmt.Printf("🗑️ 移除凭证: %s\n", sourceName)
// 移除凭证(通过重建凭证映射)
if config.PackageSourceCredentials != nil {
delete(config.PackageSourceCredentials.Sources, sourceName)
fmt.Printf("✅ 已移除 %s 的凭证\n", sourceName)
}
// 验证移除
credential := api.GetCredential(config, sourceName)
if credential == nil {
fmt.Printf("✅ 确认凭证已移除: %s\n", sourceName)
} else {
fmt.Printf("❌ 凭证移除失败: %s\n", sourceName)
}
}
}
func getEnvOrDefault(envVar, defaultValue string) string {
if value := os.Getenv(envVar); value != "" {
return value
}
return defaultValue
}
示例 3: 企业凭证管理
企业环境中的凭证管理最佳实践:
go
package main
import (
"fmt"
"log"
"os"
"path/filepath"
"strings"
"github.com/scagogogo/nuget-config-parser/pkg/nuget"
)
func main() {
api := nuget.NewAPI()
fmt.Println("=== 企业凭证管理 ===")
// 创建凭证管理器
credManager := NewEnterpriseCredentialManager(api)
// 加载企业凭证配置
err := credManager.LoadEnterpriseCredentials()
if err != nil {
log.Fatalf("加载企业凭证失败: %v", err)
}
// 为不同环境创建配置
environments := []string{"development", "staging", "production"}
for _, env := range environments {
fmt.Printf("\n配置 %s 环境凭证...\n", env)
config, err := credManager.CreateEnvironmentConfig(env)
if err != nil {
log.Printf("创建 %s 环境配置失败: %v", env, err)
continue
}
// 保存环境配置
configPath := fmt.Sprintf("Enterprise.%s.Config", env)
err = api.SaveConfig(config, configPath)
if err != nil {
log.Printf("保存 %s 配置失败: %v", env, err)
continue
}
fmt.Printf("✅ %s 环境配置已保存\n", env)
// 显示凭证摘要(不显示敏感信息)
credManager.DisplayCredentialSummary(config, env)
}
// 演示凭证轮换
credManager.DemonstrateCredentialRotation()
fmt.Println("\n企业凭证管理完成")
}
type EnterpriseCredentialManager struct {
api *nuget.API
credentials map[string]EnterpriseCredential
}
type EnterpriseCredential struct {
SourceName string
URL string
Environment []string // 适用的环境
AuthType string
Username string
Password string
Description string
LastUpdated string
}
func NewEnterpriseCredentialManager(api *nuget.API) *EnterpriseCredentialManager {
return &EnterpriseCredentialManager{
api: api,
credentials: make(map[string]EnterpriseCredential),
}
}
func (ecm *EnterpriseCredentialManager) LoadEnterpriseCredentials() error {
fmt.Println("加载企业凭证配置...")
// 模拟从安全存储加载凭证
enterpriseCredentials := []EnterpriseCredential{
{
SourceName: "enterprise-stable",
URL: "https://nuget.enterprise.com/stable",
Environment: []string{"development", "staging", "production"},
AuthType: "basic",
Username: "enterprise_service",
Password: "enterprise_secure_pass_2024",
Description: "企业稳定包源",
LastUpdated: "2024-01-15",
},
{
SourceName: "enterprise-dev",
URL: "https://dev.nuget.enterprise.com",
Environment: []string{"development"},
AuthType: "basic",
Username: "dev_service",
Password: "dev_pass_2024",
Description: "企业开发包源",
LastUpdated: "2024-01-10",
},
{
SourceName: "enterprise-staging",
URL: "https://staging.nuget.enterprise.com",
Environment: []string{"staging"},
AuthType: "basic",
Username: "staging_service",
Password: "staging_pass_2024",
Description: "企业预发布包源",
LastUpdated: "2024-01-12",
},
{
SourceName: "enterprise-prod",
URL: "https://prod.nuget.enterprise.com",
Environment: []string{"production"},
AuthType: "basic",
Username: "prod_service",
Password: "prod_secure_pass_2024",
Description: "企业生产包源",
LastUpdated: "2024-01-14",
},
{
SourceName: "azure-artifacts-enterprise",
URL: "https://pkgs.dev.azure.com/enterprise/_packaging/main/nuget/v3/index.json",
Environment: []string{"development", "staging", "production"},
AuthType: "token",
Username: "PAT",
Password: "azure_pat_token_enterprise_2024",
Description: "企业Azure DevOps包源",
LastUpdated: "2024-01-16",
},
}
for _, cred := range enterpriseCredentials {
ecm.credentials[cred.SourceName] = cred
fmt.Printf("✅ 加载凭证: %s (%s)\n", cred.SourceName, cred.Description)
}
fmt.Printf("总共加载 %d 个企业凭证\n", len(ecm.credentials))
return nil
}
func (ecm *EnterpriseCredentialManager) CreateEnvironmentConfig(environment string) (*types.NuGetConfig, error) {
config := ecm.api.CreateDefaultConfig()
// 添加公共源
ecm.api.AddPackageSource(config, "nuget.org", "https://api.nuget.org/v3/index.json", "3")
// 添加适用于此环境的企业源
addedCount := 0
for _, cred := range ecm.credentials {
// 检查凭证是否适用于当前环境
if ecm.isCredentialApplicable(cred, environment) {
// 添加包源
ecm.api.AddPackageSource(config, cred.SourceName, cred.URL, "3")
// 添加凭证
ecm.api.AddCredential(config, cred.SourceName, cred.Username, cred.Password)
addedCount++
fmt.Printf(" ✅ 添加: %s\n", cred.SourceName)
}
}
// 根据环境设置特定配置
ecm.configureEnvironmentSpecificSettings(config, environment)
fmt.Printf(" 为 %s 环境添加了 %d 个凭证\n", environment, addedCount)
return config, nil
}
func (ecm *EnterpriseCredentialManager) isCredentialApplicable(cred EnterpriseCredential, environment string) bool {
for _, env := range cred.Environment {
if env == environment {
return true
}
}
return false
}
func (ecm *EnterpriseCredentialManager) configureEnvironmentSpecificSettings(config *types.NuGetConfig, environment string) {
switch environment {
case "development":
ecm.api.AddConfigOption(config, "globalPackagesFolder", "./dev-packages")
ecm.api.AddConfigOption(config, "dependencyVersion", "Highest")
ecm.api.SetActivePackageSource(config, "enterprise-dev", "https://dev.nuget.enterprise.com")
case "staging":
ecm.api.AddConfigOption(config, "globalPackagesFolder", "/staging/packages")
ecm.api.AddConfigOption(config, "dependencyVersion", "HighestMinor")
ecm.api.SetActivePackageSource(config, "enterprise-staging", "https://staging.nuget.enterprise.com")
case "production":
ecm.api.AddConfigOption(config, "globalPackagesFolder", "/prod/packages")
ecm.api.AddConfigOption(config, "dependencyVersion", "Exact")
ecm.api.AddConfigOption(config, "signatureValidationMode", "require")
ecm.api.SetActivePackageSource(config, "enterprise-prod", "https://prod.nuget.enterprise.com")
// 生产环境禁用外部源
ecm.api.DisablePackageSource(config, "nuget.org")
}
}
func (ecm *EnterpriseCredentialManager) DisplayCredentialSummary(config *types.NuGetConfig, environment string) {
fmt.Printf("\n--- %s 环境凭证摘要 ---\n", strings.ToUpper(environment))
if config.PackageSourceCredentials == nil {
fmt.Println("无配置凭证")
return
}
fmt.Printf("已配置凭证的源 (%d):\n", len(config.PackageSourceCredentials.Sources))
for sourceName, cred := range config.PackageSourceCredentials.Sources {
// 查找原始凭证信息
if enterpriseCred, exists := ecm.credentials[sourceName]; exists {
fmt.Printf(" - %s\n", sourceName)
fmt.Printf(" 描述: %s\n", enterpriseCred.Description)
fmt.Printf(" 用户: %s\n", cred.Username.Value)
fmt.Printf(" 认证类型: %s\n", enterpriseCred.AuthType)
fmt.Printf(" 最后更新: %s\n", enterpriseCred.LastUpdated)
} else {
fmt.Printf(" - %s (用户: %s)\n", sourceName, cred.Username.Value)
}
}
}
func (ecm *EnterpriseCredentialManager) DemonstrateCredentialRotation() {
fmt.Println("\n=== 凭证轮换演示 ===")
// 模拟定期凭证轮换
rotationCandidates := []string{"enterprise-stable", "azure-artifacts-enterprise"}
for _, sourceName := range rotationCandidates {
if cred, exists := ecm.credentials[sourceName]; exists {
fmt.Printf("🔄 轮换凭证: %s\n", sourceName)
// 生成新密码(实际应用中应使用安全的密码生成器)
newPassword := fmt.Sprintf("%s_rotated_2024", cred.Password)
// 更新凭证
cred.Password = newPassword
cred.LastUpdated = "2024-01-20"
ecm.credentials[sourceName] = cred
fmt.Printf("✅ %s 凭证已轮换\n", sourceName)
}
}
fmt.Println("凭证轮换完成")
}
安全最佳实践
1. 凭证存储
go
// 不推荐:明文存储
api.AddCredential(config, "source", "user", "plaintext_password")
// 推荐:从安全存储获取
password := getFromSecureStore("source_password")
api.AddCredential(config, "source", "user", password)
2. 环境变量使用
go
// 从环境变量获取敏感信息
username := os.Getenv("NUGET_USERNAME")
password := os.Getenv("NUGET_PASSWORD")
if username == "" || password == "" {
log.Fatal("缺少必需的凭证环境变量")
}
api.AddCredential(config, "private-source", username, password)
3. 凭证轮换
go
// 定期更新凭证
func rotateCredentials(api *nuget.API, config *types.NuGetConfig) {
// 获取新凭证
newPassword := generateSecurePassword()
// 更新配置
api.AddCredential(config, "source", "user", newPassword)
// 记录轮换
log.Printf("凭证已轮换: %s", time.Now().Format("2006-01-02"))
}
关键概念
认证类型
- 基本认证 - 用户名/密码
- 令牌认证 - API令牌或PAT
- API密钥 - 单一密钥认证
安全考虑
- 加密存储 - 不要明文存储密码
- 环境隔离 - 不同环境使用不同凭证
- 定期轮换 - 定期更新密码和令牌
- 最小权限 - 只授予必要的权限
下一步
掌握凭证管理后:
本指南为 NuGet 凭证管理提供了全面的示例,涵盖了从基本认证到企业级安全管理的各种场景。