mirror of
https://github.com/skyle1995/NetworkAuth.git
synced 2026-05-25 02:24:05 +08:00
New administrator authentication method
New configuration generation scheme
This commit is contained in:
212
config/config.go
212
config/config.go
@@ -2,7 +2,7 @@ package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
@@ -11,8 +11,156 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
//go:embed config.json
|
||||
var DefaultConfig string
|
||||
// ServerConfig 服务器配置结构体
|
||||
// 包含服务器运行相关的配置信息
|
||||
type ServerConfig struct {
|
||||
Host string `json:"host" mapstructure:"host"` // 服务器监听地址
|
||||
Port int `json:"port" mapstructure:"port"` // 服务器监听端口
|
||||
Mode string `json:"mode" mapstructure:"mode"` // 运行模式(debug/release)
|
||||
Dist string `json:"dist" mapstructure:"dist"` // 静态文件目录
|
||||
}
|
||||
|
||||
// DatabaseConfig 数据库配置结构体
|
||||
// 包含数据库连接相关的配置信息
|
||||
type DatabaseConfig struct {
|
||||
Type string `json:"type" mapstructure:"type"` // 数据库类型(mysql/sqlite)
|
||||
MySQL MySQLConfig `json:"mysql" mapstructure:"mysql"` // MySQL配置
|
||||
SQLite SQLiteConfig `json:"sqlite" mapstructure:"sqlite"` // SQLite配置
|
||||
}
|
||||
|
||||
// MySQLConfig MySQL数据库配置结构体
|
||||
// 包含MySQL数据库连接的详细配置信息
|
||||
type MySQLConfig struct {
|
||||
Host string `json:"host" mapstructure:"host"` // 数据库主机地址
|
||||
Port int `json:"port" mapstructure:"port"` // 数据库端口
|
||||
Username string `json:"username" mapstructure:"username"` // 数据库用户名
|
||||
Password string `json:"password" mapstructure:"password"` // 数据库密码
|
||||
Database string `json:"database" mapstructure:"database"` // 数据库名称
|
||||
Charset string `json:"charset" mapstructure:"charset"` // 字符集
|
||||
MaxIdleConns int `json:"max_idle_conns" mapstructure:"max_idle_conns"` // 最大空闲连接数
|
||||
MaxOpenConns int `json:"max_open_conns" mapstructure:"max_open_conns"` // 最大打开连接数
|
||||
}
|
||||
|
||||
// SQLiteConfig SQLite数据库配置结构体
|
||||
// 包含SQLite数据库文件路径配置
|
||||
type SQLiteConfig struct {
|
||||
Path string `json:"path" mapstructure:"path"` // 数据库文件路径
|
||||
}
|
||||
|
||||
// RedisConfig Redis配置结构体
|
||||
// 包含Redis连接相关的配置信息
|
||||
type RedisConfig struct {
|
||||
Host string `json:"host" mapstructure:"host"` // Redis服务器地址
|
||||
Port int `json:"port" mapstructure:"port"` // Redis服务器端口
|
||||
Password string `json:"password" mapstructure:"password"` // Redis密码
|
||||
DB int `json:"db" mapstructure:"db"` // Redis数据库编号
|
||||
}
|
||||
|
||||
// LogConfig 日志配置结构体
|
||||
// 包含日志记录相关的配置信息
|
||||
type LogConfig struct {
|
||||
Level string `json:"level" mapstructure:"level"` // 日志级别
|
||||
File string `json:"file" mapstructure:"file"` // 日志文件路径
|
||||
MaxSize int `json:"max_size" mapstructure:"max_size"` // 单个日志文件最大大小(MB)
|
||||
MaxBackups int `json:"max_backups" mapstructure:"max_backups"` // 保留的旧日志文件数量
|
||||
MaxAge int `json:"max_age" mapstructure:"max_age"` // 日志文件保留天数
|
||||
}
|
||||
|
||||
// CookieConfig Cookie配置结构体
|
||||
// 包含Cookie相关的安全配置信息
|
||||
type CookieConfig struct {
|
||||
Secure bool `json:"secure" mapstructure:"secure"` // 是否只在HTTPS下发送Cookie
|
||||
SameSite string `json:"same_site" mapstructure:"same_site"` // SameSite属性(Strict/Lax/None)
|
||||
Domain string `json:"domain" mapstructure:"domain"` // Cookie域名
|
||||
MaxAge int `json:"max_age" mapstructure:"max_age"` // Cookie最大存活时间(秒)
|
||||
}
|
||||
|
||||
// SecurityConfig 安全配置结构体
|
||||
// 包含应用程序安全相关的配置信息
|
||||
type SecurityConfig struct {
|
||||
JWTSecret string `json:"jwt_secret" mapstructure:"jwt_secret"` // JWT签名密钥
|
||||
EncryptionKey string `json:"encryption_key" mapstructure:"encryption_key"` // 数据加密密钥
|
||||
JWTRefreshThresholdHours int `json:"jwt_refresh_threshold_hours" mapstructure:"jwt_refresh_threshold_hours"` // JWT令牌刷新阈值(小时)
|
||||
Cookie CookieConfig `json:"cookie" mapstructure:"cookie"` // Cookie配置
|
||||
}
|
||||
|
||||
// AppConfig 应用配置结构体
|
||||
type AppConfig struct {
|
||||
Server ServerConfig `json:"server" mapstructure:"server"`
|
||||
Database DatabaseConfig `json:"database" mapstructure:"database"`
|
||||
Redis RedisConfig `json:"redis" mapstructure:"redis"`
|
||||
Log LogConfig `json:"log" mapstructure:"log"`
|
||||
Security SecurityConfig `json:"security" mapstructure:"security"`
|
||||
}
|
||||
|
||||
// GetDefaultAppConfig 获取默认应用配置
|
||||
func GetDefaultAppConfig() *AppConfig {
|
||||
return &AppConfig{
|
||||
Server: ServerConfig{
|
||||
Host: "0.0.0.0",
|
||||
Port: 8080,
|
||||
Mode: "debug",
|
||||
Dist: "",
|
||||
},
|
||||
Database: DatabaseConfig{
|
||||
Type: "sqlite",
|
||||
MySQL: MySQLConfig{
|
||||
Host: "localhost",
|
||||
Port: 3306,
|
||||
Username: "root",
|
||||
Password: "password",
|
||||
Database: "networkdev",
|
||||
Charset: "utf8mb4",
|
||||
MaxIdleConns: 10,
|
||||
MaxOpenConns: 100,
|
||||
},
|
||||
SQLite: SQLiteConfig{
|
||||
Path: "./database.db",
|
||||
},
|
||||
},
|
||||
Redis: RedisConfig{
|
||||
Host: "localhost",
|
||||
Port: 6379,
|
||||
Password: "",
|
||||
DB: 0,
|
||||
},
|
||||
Log: LogConfig{
|
||||
Level: "info",
|
||||
File: "./logs/app.log",
|
||||
MaxSize: 100,
|
||||
MaxBackups: 5,
|
||||
MaxAge: 30,
|
||||
},
|
||||
Security: SecurityConfig{
|
||||
JWTSecret: "",
|
||||
EncryptionKey: "",
|
||||
JWTRefreshThresholdHours: 6,
|
||||
Cookie: CookieConfig{
|
||||
Secure: true,
|
||||
SameSite: "Lax",
|
||||
Domain: "",
|
||||
MaxAge: 86400,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetSecureDefaultAppConfig 获取带有安全密钥的默认应用配置
|
||||
func GetSecureDefaultAppConfig() (*AppConfig, error) {
|
||||
config := GetDefaultAppConfig()
|
||||
|
||||
// 生成安全密钥
|
||||
jwtSecret, encryptionKey, err := GenerateSecureKeys()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 设置安全密钥
|
||||
config.Security.JWTSecret = jwtSecret
|
||||
config.Security.EncryptionKey = encryptionKey
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// Init 初始化配置文件
|
||||
func Init(cfgFilePath string) {
|
||||
@@ -24,7 +172,31 @@ func Init(cfgFilePath string) {
|
||||
var pathError *fs.PathError
|
||||
if errors.As(err, &pathError) {
|
||||
log.Warn("未找到配置文件,使用默认配置")
|
||||
err = os.WriteFile(cfgFilePath, []byte(DefaultConfig), 0o644)
|
||||
|
||||
// 生成带有安全密钥的默认配置
|
||||
defaultConfig, configErr := GetSecureDefaultAppConfig()
|
||||
if configErr != nil {
|
||||
log.WithFields(
|
||||
log.Fields{
|
||||
"err": configErr,
|
||||
},
|
||||
).Error("生成安全配置失败,使用基础默认配置")
|
||||
defaultConfig = GetDefaultAppConfig()
|
||||
}
|
||||
|
||||
// 将配置结构体转换为JSON
|
||||
configBytes, marshalErr := json.MarshalIndent(defaultConfig, "", " ")
|
||||
if marshalErr != nil {
|
||||
log.WithFields(
|
||||
log.Fields{
|
||||
"err": marshalErr,
|
||||
},
|
||||
).Fatal("序列化默认配置失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 写入配置文件
|
||||
err = os.WriteFile(cfgFilePath, configBytes, 0o644)
|
||||
if err != nil {
|
||||
log.WithFields(
|
||||
log.Fields{
|
||||
@@ -36,16 +208,17 @@ func Init(cfgFilePath string) {
|
||||
log.Fields{
|
||||
"file": cfgFilePath,
|
||||
},
|
||||
).Info("写入默认配置文件成功")
|
||||
).Info("写入默认配置文件成功(已生成安全密钥)")
|
||||
}
|
||||
// 写完默认配置后再读一次
|
||||
err = viper.ReadConfig(bytes.NewBuffer([]byte(DefaultConfig)))
|
||||
|
||||
// 将配置加载到viper中
|
||||
err = viper.ReadConfig(bytes.NewBuffer(configBytes))
|
||||
if err != nil {
|
||||
log.WithFields(
|
||||
log.Fields{
|
||||
"err": err,
|
||||
},
|
||||
).Error("读取默认配置文件失败")
|
||||
).Error("读取默认配置失败")
|
||||
} else {
|
||||
log.Info("已成功读取默认配置")
|
||||
}
|
||||
@@ -63,8 +236,8 @@ func Init(cfgFilePath string) {
|
||||
},
|
||||
).Info("使用配置文件")
|
||||
|
||||
// 验证配置并设置默认值
|
||||
if _, err := ValidateAndSetDefaults(); err != nil {
|
||||
// 验证配置
|
||||
if _, err := ValidateConfig(); err != nil {
|
||||
log.WithFields(
|
||||
log.Fields{
|
||||
"err": err,
|
||||
@@ -75,5 +248,22 @@ func Init(cfgFilePath string) {
|
||||
|
||||
// CreateDefaultConfig 创建默认配置文件
|
||||
func CreateDefaultConfig(filePath string) error {
|
||||
return os.WriteFile(filePath, []byte(DefaultConfig), 0o644)
|
||||
// 生成带有安全密钥的默认配置
|
||||
defaultConfig, err := GetSecureDefaultAppConfig()
|
||||
if err != nil {
|
||||
log.WithFields(
|
||||
log.Fields{
|
||||
"err": err,
|
||||
},
|
||||
).Error("生成安全配置失败,使用基础默认配置")
|
||||
defaultConfig = GetDefaultAppConfig()
|
||||
}
|
||||
|
||||
// 将配置结构体转换为JSON
|
||||
configBytes, err := json.MarshalIndent(defaultConfig, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.WriteFile(filePath, configBytes, 0o644)
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
{
|
||||
"server": {
|
||||
"host": "0.0.0.0",
|
||||
"port": 8080,
|
||||
"mode": "debug",
|
||||
"dist": ""
|
||||
},
|
||||
"database": {
|
||||
"type": "sqlite",
|
||||
"mysql": {
|
||||
"host": "localhost",
|
||||
"port": 3306,
|
||||
"username": "root",
|
||||
"password": "password",
|
||||
"database": "networkdev",
|
||||
"charset": "utf8mb4",
|
||||
"max_idle_conns": 10,
|
||||
"max_open_conns": 100
|
||||
},
|
||||
"sqlite": {
|
||||
"path": "./database.db"
|
||||
}
|
||||
},
|
||||
"redis": {
|
||||
"host": "localhost",
|
||||
"port": 6379,
|
||||
"password": "",
|
||||
"db": 0
|
||||
},
|
||||
"log": {
|
||||
"level": "info",
|
||||
"file": "./logs/app.log",
|
||||
"max_size": 100,
|
||||
"max_backups": 5,
|
||||
"max_age": 30
|
||||
},
|
||||
"security": {
|
||||
"jwt_secret": "your-jwt-secret-key",
|
||||
"encryption_key": "your-encryption-key",
|
||||
"jwt_refresh_threshold_hours": 6,
|
||||
"cookie": {
|
||||
"secure": false,
|
||||
"same_site": "Lax",
|
||||
"domain": "",
|
||||
"max_age": 86400
|
||||
}
|
||||
}
|
||||
}
|
||||
49
config/security.go
Normal file
49
config/security.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// GenerateSecureJWTSecret 生成安全的JWT密钥
|
||||
// 生成64字节(512位)的随机密钥,使用base64编码
|
||||
func GenerateSecureJWTSecret() (string, error) {
|
||||
// 生成64字节的随机数据
|
||||
bytes := make([]byte, 64)
|
||||
if _, err := rand.Read(bytes); err != nil {
|
||||
return "", fmt.Errorf("生成JWT密钥失败: %w", err)
|
||||
}
|
||||
|
||||
// 使用base64编码,便于配置文件存储
|
||||
return base64.StdEncoding.EncodeToString(bytes), nil
|
||||
}
|
||||
|
||||
// GenerateSecureEncryptionKey 生成安全的加密密钥
|
||||
// 生成32字节(256位)的随机密钥,使用十六进制编码
|
||||
func GenerateSecureEncryptionKey() (string, error) {
|
||||
// 生成32字节的随机数据(AES-256)
|
||||
bytes := make([]byte, 32)
|
||||
if _, err := rand.Read(bytes); err != nil {
|
||||
return "", fmt.Errorf("生成加密密钥失败: %w", err)
|
||||
}
|
||||
|
||||
// 使用十六进制编码
|
||||
return hex.EncodeToString(bytes), nil
|
||||
}
|
||||
|
||||
// GenerateSecureKeys 生成所有安全密钥
|
||||
func GenerateSecureKeys() (jwtSecret, encryptionKey string, err error) {
|
||||
jwtSecret, err = GenerateSecureJWTSecret()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
encryptionKey, err = GenerateSecureEncryptionKey()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return jwtSecret, encryptionKey, nil
|
||||
}
|
||||
@@ -13,80 +13,8 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// ServerConfig 服务器配置结构体
|
||||
// 包含HTTP服务器的基本配置信息
|
||||
type ServerConfig struct {
|
||||
Host string `json:"host" mapstructure:"host"` // 服务器监听地址
|
||||
Port int `json:"port" mapstructure:"port"` // 服务器监听端口
|
||||
Mode string `json:"mode" mapstructure:"mode"` // 运行模式(debug/release)
|
||||
Dist string `json:"dist" mapstructure:"dist"` // 静态文件目录
|
||||
}
|
||||
|
||||
// DatabaseConfig 数据库配置结构体
|
||||
// 支持MySQL和SQLite两种数据库类型
|
||||
type DatabaseConfig struct {
|
||||
Type string `json:"type" mapstructure:"type"` // 数据库类型(mysql/sqlite)
|
||||
MySQL MySQLConfig `json:"mysql" mapstructure:"mysql"` // MySQL配置
|
||||
SQLite SQLiteConfig `json:"sqlite" mapstructure:"sqlite"` // SQLite配置
|
||||
}
|
||||
|
||||
// MySQLConfig MySQL数据库配置结构体
|
||||
// 包含MySQL数据库连接和连接池的配置信息
|
||||
type MySQLConfig struct {
|
||||
Host string `json:"host" mapstructure:"host"` // 数据库主机地址
|
||||
Port int `json:"port" mapstructure:"port"` // 数据库端口
|
||||
Username string `json:"username" mapstructure:"username"` // 数据库用户名
|
||||
Password string `json:"password" mapstructure:"password"` // 数据库密码
|
||||
Database string `json:"database" mapstructure:"database"` // 数据库名称
|
||||
Charset string `json:"charset" mapstructure:"charset"` // 字符集
|
||||
MaxIdleConns int `json:"max_idle_conns" mapstructure:"max_idle_conns"` // 最大空闲连接数
|
||||
MaxOpenConns int `json:"max_open_conns" mapstructure:"max_open_conns"` // 最大打开连接数
|
||||
}
|
||||
|
||||
// SQLiteConfig SQLite数据库配置结构体
|
||||
// 包含SQLite数据库文件路径配置
|
||||
type SQLiteConfig struct {
|
||||
Path string `json:"path" mapstructure:"path"` // 数据库文件路径
|
||||
}
|
||||
|
||||
// RedisConfig Redis配置结构体
|
||||
// 包含Redis缓存服务器的连接配置
|
||||
type RedisConfig struct {
|
||||
Host string `json:"host" mapstructure:"host"` // Redis服务器地址
|
||||
Port int `json:"port" mapstructure:"port"` // Redis服务器端口
|
||||
Password string `json:"password" mapstructure:"password"` // Redis密码
|
||||
DB int `json:"db" mapstructure:"db"` // Redis数据库编号
|
||||
}
|
||||
|
||||
// LogConfig 日志配置结构体
|
||||
// 包含日志记录的相关配置信息
|
||||
type LogConfig struct {
|
||||
Level string `json:"level" mapstructure:"level"` // 日志级别
|
||||
File string `json:"file" mapstructure:"file"` // 日志文件路径
|
||||
MaxSize int `json:"max_size" mapstructure:"max_size"` // 单个日志文件最大大小(MB)
|
||||
MaxBackups int `json:"max_backups" mapstructure:"max_backups"` // 保留的旧日志文件数量
|
||||
MaxAge int `json:"max_age" mapstructure:"max_age"` // 日志文件保留天数
|
||||
}
|
||||
|
||||
// SecurityConfig 安全配置结构体
|
||||
// 包含应用程序安全相关的配置信息
|
||||
type SecurityConfig struct {
|
||||
JWTSecret string `json:"jwt_secret" mapstructure:"jwt_secret"` // JWT签名密钥
|
||||
EncryptionKey string `json:"encryption_key" mapstructure:"encryption_key"` // 数据加密密钥
|
||||
JWTRefreshThresholdHours int `json:"jwt_refresh_threshold_hours" mapstructure:"jwt_refresh_threshold_hours"` // JWT令牌刷新阈值(小时)
|
||||
}
|
||||
|
||||
// AppConfig 应用配置结构体
|
||||
type AppConfig struct {
|
||||
Server ServerConfig `json:"server" mapstructure:"server"`
|
||||
Database DatabaseConfig `json:"database" mapstructure:"database"`
|
||||
Redis RedisConfig `json:"redis" mapstructure:"redis"`
|
||||
Log LogConfig `json:"log" mapstructure:"log"`
|
||||
Security SecurityConfig `json:"security" mapstructure:"security"`
|
||||
}
|
||||
|
||||
// ValidateAndSetDefaults 验证配置并设置默认值
|
||||
func ValidateAndSetDefaults() (*AppConfig, error) {
|
||||
// ValidateConfig 验证配置
|
||||
func ValidateConfig() (*AppConfig, error) {
|
||||
var config AppConfig
|
||||
|
||||
// 解析配置到结构体
|
||||
@@ -94,9 +22,6 @@ func ValidateAndSetDefaults() (*AppConfig, error) {
|
||||
return nil, fmt.Errorf("解析配置失败: %w", err)
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
setDefaults(&config)
|
||||
|
||||
// 验证配置
|
||||
if err := validateConfig(&config); err != nil {
|
||||
return nil, fmt.Errorf("配置验证失败: %w", err)
|
||||
@@ -106,74 +31,6 @@ func ValidateAndSetDefaults() (*AppConfig, error) {
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
// setDefaults 设置默认值
|
||||
func setDefaults(config *AppConfig) {
|
||||
// 服务器默认值
|
||||
if config.Server.Host == "" {
|
||||
config.Server.Host = "0.0.0.0"
|
||||
}
|
||||
if config.Server.Port == 0 {
|
||||
config.Server.Port = 8080
|
||||
}
|
||||
if config.Server.Mode == "" {
|
||||
config.Server.Mode = "debug"
|
||||
}
|
||||
|
||||
// 数据库默认值
|
||||
if config.Database.Type == "" {
|
||||
config.Database.Type = "sqlite"
|
||||
}
|
||||
if config.Database.MySQL.Port == 0 {
|
||||
config.Database.MySQL.Port = 3306
|
||||
}
|
||||
if config.Database.MySQL.Charset == "" {
|
||||
config.Database.MySQL.Charset = "utf8mb4"
|
||||
}
|
||||
if config.Database.MySQL.MaxIdleConns == 0 {
|
||||
config.Database.MySQL.MaxIdleConns = 10
|
||||
}
|
||||
if config.Database.MySQL.MaxOpenConns == 0 {
|
||||
config.Database.MySQL.MaxOpenConns = 100
|
||||
}
|
||||
if config.Database.SQLite.Path == "" {
|
||||
config.Database.SQLite.Path = "./database.db"
|
||||
}
|
||||
|
||||
// Redis默认值
|
||||
if config.Redis.Host == "" {
|
||||
config.Redis.Host = "localhost"
|
||||
}
|
||||
if config.Redis.Port == 0 {
|
||||
config.Redis.Port = 6379
|
||||
}
|
||||
|
||||
// 日志默认值
|
||||
if config.Log.Level == "" {
|
||||
config.Log.Level = "info"
|
||||
}
|
||||
// 不为空的日志文件路径设置默认值,保持为空表示只输出到控制台
|
||||
if config.Log.MaxSize == 0 {
|
||||
config.Log.MaxSize = 100
|
||||
}
|
||||
if config.Log.MaxBackups == 0 {
|
||||
config.Log.MaxBackups = 5
|
||||
}
|
||||
if config.Log.MaxAge == 0 {
|
||||
config.Log.MaxAge = 30
|
||||
}
|
||||
|
||||
// 安全配置默认值
|
||||
if config.Security.JWTSecret == "" || config.Security.JWTSecret == "your-jwt-secret-key" {
|
||||
config.Security.JWTSecret = "default-jwt-secret-change-in-production"
|
||||
}
|
||||
if config.Security.EncryptionKey == "" || config.Security.EncryptionKey == "your-encryption-key" {
|
||||
config.Security.EncryptionKey = "default-encryption-key-change-in-production"
|
||||
}
|
||||
if config.Security.JWTRefreshThresholdHours == 0 {
|
||||
config.Security.JWTRefreshThresholdHours = 6
|
||||
}
|
||||
}
|
||||
|
||||
// validateConfig 验证配置
|
||||
func validateConfig(config *AppConfig) error {
|
||||
// 验证服务器配置
|
||||
|
||||
Reference in New Issue
Block a user