283 lines
15 KiB
Go
283 lines
15 KiB
Go
/*
|
||
Package config 负责管理 Go LDAP Admin 系统的所有配置信息
|
||
|
||
该包使用 Viper 库来读取和管理配置文件,支持:
|
||
- YAML 格式的配置文件
|
||
- 环境变量覆盖配置
|
||
- 配置文件热更新
|
||
- RSA 密钥嵌入
|
||
|
||
配置文件结构包括:
|
||
- 系统配置:运行模式、端口、URL前缀等
|
||
- 日志配置:日志级别、路径、轮转策略等
|
||
- 数据库配置:MySQL/SQLite 连接信息
|
||
- LDAP 配置:OpenLDAP 服务器连接信息
|
||
- JWT 配置:Token 生成和验证配置
|
||
- 企业 IM 配置:钉钉、企业微信、飞书集成配置
|
||
*/
|
||
package config
|
||
|
||
import (
|
||
_ "embed"
|
||
"fmt"
|
||
"os"
|
||
"strconv"
|
||
|
||
"github.com/fsnotify/fsnotify"
|
||
"github.com/spf13/viper"
|
||
"go.uber.org/zap/zapcore"
|
||
)
|
||
|
||
// Conf 全局配置变量,存储从配置文件和环境变量中读取的所有配置信息
|
||
// 系统启动时通过 InitConfig() 函数初始化,之后可在全局范围内访问
|
||
var Conf = new(config)
|
||
|
||
// RSA 密钥文件嵌入
|
||
// 使用 go:embed 指令将 RSA 私钥和公钥文件嵌入到二进制文件中
|
||
// 用于 JWT Token 的签名和验证
|
||
|
||
//go:embed go-ldap-admin-priv.pem
|
||
var priv []byte // RSA 私钥,用于 JWT Token 签名
|
||
|
||
//go:embed go-ldap-admin-pub.pem
|
||
var pub []byte // RSA 公钥,用于 JWT Token 验证
|
||
|
||
// config 主配置结构体,包含系统所有模块的配置信息
|
||
// 使用 mapstructure 标签将 YAML 配置映射到结构体字段
|
||
// YAML 文件中使用 "-" 分隔单词,映射到 Go 的驼峰命名
|
||
type config struct {
|
||
System *SystemConfig `mapstructure:"system" json:"system"` // 系统基础配置
|
||
Logs *LogsConfig `mapstructure:"logs" json:"logs"` // 日志配置
|
||
Database *Database `mapstructure:"database" json:"database"` // 数据库类型配置
|
||
Mysql *MysqlConfig `mapstructure:"mysql" json:"mysql"` // MySQL 数据库配置
|
||
Jwt *JwtConfig `mapstructure:"jwt" json:"jwt"` // JWT 认证配置
|
||
RateLimit *RateLimitConfig `mapstructure:"rate-limit" json:"rateLimit"` // 限流配置
|
||
Ldap *LdapConfig `mapstructure:"ldap" json:"ldap"` // LDAP 服务器配置
|
||
Email *EmailConfig `mapstructure:"email" json:"email"` // 邮件服务配置
|
||
DingTalk *DingTalkConfig `mapstructure:"dingtalk" json:"dingTalk"` // 钉钉集成配置
|
||
WeCom *WeComConfig `mapstructure:"wecom" json:"weCom"` // 企业微信集成配置
|
||
FeiShu *FeiShuConfig `mapstructure:"feishu" json:"feiShu"` // 飞书集成配置
|
||
}
|
||
|
||
// InitConfig 初始化系统配置
|
||
// 该函数负责:
|
||
// 1. 读取 config.yml 配置文件
|
||
// 2. 设置配置文件热更新监听
|
||
// 3. 加载嵌入的 RSA 密钥
|
||
// 4. 支持环境变量覆盖配置
|
||
func InitConfig() {
|
||
// ==================== 配置文件读取 ====================
|
||
|
||
// 获取当前工作目录
|
||
workDir, err := os.Getwd()
|
||
if err != nil {
|
||
panic(fmt.Errorf("读取应用目录失败:%s", err))
|
||
}
|
||
|
||
// 配置 Viper 读取配置文件
|
||
viper.SetConfigName("config") // 配置文件名(不包含扩展名)
|
||
viper.SetConfigType("yml") // 配置文件类型
|
||
viper.AddConfigPath(workDir + "/") // 配置文件搜索路径
|
||
|
||
// 读取配置文件内容
|
||
err = viper.ReadInConfig()
|
||
if err != nil {
|
||
panic(fmt.Errorf("读取配置文件失败:%s", err))
|
||
}
|
||
|
||
// ==================== 配置热更新 ====================
|
||
|
||
// 启用配置文件监听,支持热更新
|
||
viper.WatchConfig()
|
||
viper.OnConfigChange(func(e fsnotify.Event) {
|
||
// 配置文件发生变化时,重新解析配置到全局变量
|
||
if err := viper.Unmarshal(Conf); err != nil {
|
||
panic(fmt.Errorf("热更新配置文件失败:%s", err))
|
||
}
|
||
// 重新加载 RSA 密钥
|
||
Conf.System.RSAPublicBytes = pub
|
||
Conf.System.RSAPrivateBytes = priv
|
||
})
|
||
|
||
// ==================== 初始配置解析 ====================
|
||
|
||
// 将配置文件内容解析到全局配置结构体
|
||
if err := viper.Unmarshal(Conf); err != nil {
|
||
panic(fmt.Errorf("初始化配置文件失败:%s", err))
|
||
}
|
||
|
||
// 加载嵌入的 RSA 密钥到配置中
|
||
Conf.System.RSAPublicBytes = pub
|
||
Conf.System.RSAPrivateBytes = priv
|
||
|
||
// ==================== 环境变量覆盖配置 ====================
|
||
// 支持通过环境变量覆盖配置文件中的设置,便于容器化部署
|
||
|
||
// 数据库配置环境变量覆盖
|
||
if dbDriver := os.Getenv("DB_DRIVER"); dbDriver != "" {
|
||
Conf.Database.Driver = dbDriver
|
||
}
|
||
if mysqlHost := os.Getenv("MYSQL_HOST"); mysqlHost != "" {
|
||
Conf.Mysql.Host = mysqlHost
|
||
}
|
||
if mysqlUsername := os.Getenv("MYSQL_USERNAME"); mysqlUsername != "" {
|
||
Conf.Mysql.Username = mysqlUsername
|
||
}
|
||
if mysqlPassword := os.Getenv("MYSQL_PASSWORD"); mysqlPassword != "" {
|
||
Conf.Mysql.Password = mysqlPassword
|
||
}
|
||
if mysqlDatabase := os.Getenv("MYSQL_DATABASE"); mysqlDatabase != "" {
|
||
Conf.Mysql.Database = mysqlDatabase
|
||
}
|
||
if mysqlPort := os.Getenv("MYSQL_PORT"); mysqlPort != "" {
|
||
if port, err := strconv.Atoi(mysqlPort); err == nil {
|
||
Conf.Mysql.Port = port
|
||
}
|
||
}
|
||
|
||
// LDAP 配置环境变量覆盖
|
||
if ldapUrl := os.Getenv("LDAP_URL"); ldapUrl != "" {
|
||
Conf.Ldap.Url = ldapUrl
|
||
}
|
||
if ldapBaseDN := os.Getenv("LDAP_BASE_DN"); ldapBaseDN != "" {
|
||
Conf.Ldap.BaseDN = ldapBaseDN
|
||
}
|
||
if ldapAdminDN := os.Getenv("LDAP_ADMIN_DN"); ldapAdminDN != "" {
|
||
Conf.Ldap.AdminDN = ldapAdminDN
|
||
}
|
||
if ldapAdminPass := os.Getenv("LDAP_ADMIN_PASS"); ldapAdminPass != "" {
|
||
Conf.Ldap.AdminPass = ldapAdminPass
|
||
}
|
||
if ldapUserDN := os.Getenv("LDAP_USER_DN"); ldapUserDN != "" {
|
||
Conf.Ldap.UserDN = ldapUserDN
|
||
}
|
||
if ldapUserInitPassword := os.Getenv("LDAP_USER_INIT_PASSWORD"); ldapUserInitPassword != "" {
|
||
Conf.Ldap.UserInitPassword = ldapUserInitPassword
|
||
}
|
||
if ldapDefaultEmailSuffix := os.Getenv("LDAP_DEFAULT_EMAIL_SUFFIX"); ldapDefaultEmailSuffix != "" {
|
||
Conf.Ldap.DefaultEmailSuffix = ldapDefaultEmailSuffix
|
||
}
|
||
if ldapUserPasswordEncryptionType := os.Getenv("LDAP_USER_PASSWORD_ENCRYPTION_TYPE"); ldapUserPasswordEncryptionType != "" {
|
||
Conf.Ldap.UserPasswordEncryptionType = ldapUserPasswordEncryptionType
|
||
}
|
||
}
|
||
|
||
// ==================== 配置结构体定义 ====================
|
||
|
||
// SystemConfig 系统基础配置
|
||
type SystemConfig struct {
|
||
Mode string `mapstructure:"mode" json:"mode"` // 运行模式:debug/release/test
|
||
UrlPathPrefix string `mapstructure:"url-path-prefix" json:"urlPathPrefix"` // API URL 前缀
|
||
Port int `mapstructure:"port" json:"port"` // HTTP 服务监听端口
|
||
InitData bool `mapstructure:"init-data" json:"initData"` // 是否初始化基础数据
|
||
RSAPublicBytes []byte `mapstructure:"-" json:"-"` // RSA 公钥字节数组(不序列化)
|
||
RSAPrivateBytes []byte `mapstructure:"-" json:"-"` // RSA 私钥字节数组(不序列化)
|
||
}
|
||
|
||
// LogsConfig 日志系统配置
|
||
type LogsConfig struct {
|
||
Level zapcore.Level `mapstructure:"level" json:"level"` // 日志级别(-1:Debug, 0:Info, 1:Warn, 2:Error, 3:DPanic, 4:Panic, 5:Fatal)
|
||
Path string `mapstructure:"path" json:"path"` // 日志文件存储路径
|
||
MaxSize int `mapstructure:"max-size" json:"maxSize"` // 单个日志文件最大大小(MB)
|
||
MaxBackups int `mapstructure:"max-backups" json:"maxBackups"` // 保留的日志文件备份数量
|
||
MaxAge int `mapstructure:"max-age" json:"maxAge"` // 日志文件保留天数
|
||
Compress bool `mapstructure:"compress" json:"compress"` // 是否压缩旧日志文件
|
||
}
|
||
|
||
// Database 数据库类型配置
|
||
type Database struct {
|
||
Driver string `mapstructure:"driver" json:"driver"` // 数据库驱动类型:mysql/sqlite3
|
||
Source string `mapstructure:"source" json:"source"` // SQLite 数据库文件路径
|
||
}
|
||
|
||
// MysqlConfig MySQL 数据库连接配置
|
||
type MysqlConfig struct {
|
||
Username string `mapstructure:"username" json:"username"` // 数据库用户名
|
||
Password string `mapstructure:"password" json:"password"` // 数据库密码
|
||
Database string `mapstructure:"database" json:"database"` // 数据库名称
|
||
Host string `mapstructure:"host" json:"host"` // 数据库主机地址
|
||
Port int `mapstructure:"port" json:"port"` // 数据库端口
|
||
Query string `mapstructure:"query" json:"query"` // 连接字符串参数
|
||
LogMode bool `mapstructure:"log-mode" json:"logMode"` // 是否开启 SQL 日志
|
||
TablePrefix string `mapstructure:"table-prefix" json:"tablePrefix"` // 数据表前缀
|
||
Charset string `mapstructure:"charset" json:"charset"` // 字符编码
|
||
Collation string `mapstructure:"collation" json:"collation"` // 字符集排序规则
|
||
}
|
||
|
||
// JwtConfig JWT 认证配置
|
||
type JwtConfig struct {
|
||
Realm string `mapstructure:"realm" json:"realm"` // JWT 标识符
|
||
Key string `mapstructure:"key" json:"key"` // JWT 签名密钥
|
||
Timeout int `mapstructure:"timeout" json:"timeout"` // Token 过期时间(小时)
|
||
MaxRefresh int `mapstructure:"max-refresh" json:"maxRefresh"` // 刷新 Token 最大过期时间(小时)
|
||
}
|
||
|
||
// RateLimitConfig 限流配置(令牌桶算法)
|
||
type RateLimitConfig struct {
|
||
FillInterval int64 `mapstructure:"fill-interval" json:"fillInterval"` // 填充一个令牌的时间间隔(毫秒)
|
||
Capacity int64 `mapstructure:"capacity" json:"capacity"` // 令牌桶容量
|
||
}
|
||
|
||
// LdapConfig LDAP 服务器连接配置
|
||
type LdapConfig struct {
|
||
Url string `mapstructure:"url" json:"url"` // LDAP 服务器地址(如:ldap://localhost:389)
|
||
MaxConn int `mapstructure:"max-conn" json:"maxConn"` // LDAP 连接池最大连接数
|
||
BaseDN string `mapstructure:"base-dn" json:"baseDN"` // LDAP 基础 DN(如:dc=example,dc=com)
|
||
AdminDN string `mapstructure:"admin-dn" json:"adminDN"` // LDAP 管理员 DN
|
||
AdminPass string `mapstructure:"admin-pass" json:"adminPass"` // LDAP 管理员密码
|
||
UserDN string `mapstructure:"user-dn" json:"userDN"` // 用户 OU DN(如:ou=people,dc=example,dc=com)
|
||
UserInitPassword string `mapstructure:"user-init-password" json:"userInitPassword"` // 新用户默认密码
|
||
GroupNameModify bool `mapstructure:"group-name-modify" json:"groupNameModify"` // 是否允许修改组 DN
|
||
UserNameModify bool `mapstructure:"user-name-modify" json:"userNameModify"` // 是否允许修改用户 DN
|
||
DefaultEmailSuffix string `mapstructure:"default-email-suffix" json:"defaultEmailSuffix"` // 默认邮箱后缀
|
||
UserPasswordEncryptionType string `mapstructure:"user-password-encryption-type" json:"userPasswordEncryptionType"` // 用户密码加密方式(ssha/clear)
|
||
}
|
||
|
||
// EmailConfig 邮件服务配置
|
||
type EmailConfig struct {
|
||
Host string `mapstructure:"host" json:"host"` // SMTP 服务器地址
|
||
Port string `mapstructure:"port" json:"port"` // SMTP 服务器端口
|
||
User string `mapstructure:"user" json:"user"` // 邮箱用户名
|
||
Pass string `mapstructure:"pass" json:"pass"` // 邮箱密码或授权码
|
||
From string `mapstructure:"from" json:"from"` // 发件人显示名称
|
||
}
|
||
|
||
// DingTalkConfig 钉钉集成配置
|
||
type DingTalkConfig struct {
|
||
AppKey string `mapstructure:"app-key" json:"appKey"` // 钉钉应用 Key
|
||
AppSecret string `mapstructure:"app-secret" json:"appSecret"` // 钉钉应用 Secret
|
||
AgentId string `mapstructure:"agent-id" json:"agentId"` // 钉钉应用 Agent ID
|
||
RootOuName string `mapstructure:"root-ou-name" json:"rootOuName"` // 根部门名称
|
||
Flag string `mapstructure:"flag" json:"flag"` // 钉钉在平台的标识
|
||
EnableSync bool `mapstructure:"enable-sync" json:"enableSync"` // 是否开启定时同步
|
||
DeptSyncTime string `mapstructure:"dept-sync-time" json:"deptSyncTime"` // 部门同步时间(Cron 表达式)
|
||
UserSyncTime string `mapstructure:"user-sync-time" json:"userSyncTime"` // 用户同步时间(Cron 表达式)
|
||
DeptList []string `mapstructure:"dept-list" json:"deptList"` // 要同步的部门列表(空则同步所有)
|
||
IsUpdateSyncd bool `mapstructure:"is-update-syncd" json:"isUpdateSyncd"` // 是否同步更新已同步的用户信息
|
||
ULeaveRange uint `mapstructure:"user-leave-range" json:"userLevelRange"` // 离职用户查询天数范围
|
||
}
|
||
|
||
// WeComConfig 企业微信集成配置
|
||
type WeComConfig struct {
|
||
Flag string `mapstructure:"flag" json:"flag"` // 企业微信在平台的标识
|
||
CorpID string `mapstructure:"corp-id" json:"corpId"` // 企业微信企业 ID
|
||
AgentID int `mapstructure:"agent-id" json:"agentId"` // 企业微信应用 ID
|
||
CorpSecret string `mapstructure:"corp-secret" json:"corpSecret"` // 企业微信应用 Secret
|
||
EnableSync bool `mapstructure:"enable-sync" json:"enableSync"` // 是否开启定时同步
|
||
DeptSyncTime string `mapstructure:"dept-sync-time" json:"deptSyncTime"` // 部门同步时间(Cron 表达式)
|
||
UserSyncTime string `mapstructure:"user-sync-time" json:"userSyncTime"` // 用户同步时间(Cron 表达式)
|
||
IsUpdateSyncd bool `mapstructure:"is-update-syncd" json:"isUpdateSyncd"` // 是否同步更新已同步的用户信息
|
||
}
|
||
|
||
// FeiShuConfig 飞书集成配置
|
||
type FeiShuConfig struct {
|
||
Flag string `mapstructure:"flag" json:"flag"` // 飞书在平台的标识
|
||
AppID string `mapstructure:"app-id" json:"appId"` // 飞书应用 ID
|
||
AppSecret string `mapstructure:"app-secret" json:"appSecret"` // 飞书应用 Secret
|
||
EnableSync bool `mapstructure:"enable-sync" json:"enableSync"` // 是否开启定时同步
|
||
DeptSyncTime string `mapstructure:"dept-sync-time" json:"deptSyncTime"` // 部门同步时间(Cron 表达式)
|
||
UserSyncTime string `mapstructure:"user-sync-time" json:"userSyncTime"` // 用户同步时间(Cron 表达式)
|
||
DeptList []string `mapstructure:"dept-list" json:"deptList"` // 要同步的部门列表(空则同步所有)
|
||
IsUpdateSyncd bool `mapstructure:"is-update-syncd" json:"isUpdateSyncd"` // 是否同步更新已同步的用户信息
|
||
}
|