You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OneAuth/models/setting.go

206 lines
8.3 KiB
Go

//
// Copyright (C) 2024 veypi <i@veypi.com>
// 2025-03-04 16:08:06
// Distributed under terms of the MIT license.
//
package models
import (
"encoding/json"
"fmt"
"strconv"
"github.com/veypi/vbase/cfg"
"github.com/veypi/vigo"
)
// Setting 系统配置表(线上配置,存储在数据库)
type Setting struct {
vigo.Model
Key string `gorm:"uniqueIndex;size:100;not null" json:"key"`
Value string `gorm:"type:text" json:"value"`
Type string `gorm:"size:20;default:'string'" json:"type"` // string/int/bool/json
Category string `gorm:"index;size:50" json:"category"`
Desc string `gorm:"size:200" json:"desc"`
UpdatedBy string `gorm:"size:36" json:"updated_by"`
}
// TableName 表名
func (Setting) TableName() string {
return "settings"
}
// 配置分类常量
const (
SettingCategoryAuth = "auth"
SettingCategoryEmail = "email"
SettingCategorySMS = "sms"
SettingCategorySecurity = "security"
SettingCategoryOAuth = "oauth"
SettingCategoryApp = "app"
)
// 配置键常量
const (
// 应用配置
SettingAppName = "app.name"
SettingAppID = "app.id"
// JWT 配置
SettingJWTSecret = "jwt.secret"
SettingJWTAccessExpiry = "jwt.access_expiry" // 单位:秒
SettingJWTRefreshExpiry = "jwt.refresh_expiry" // 单位:秒
SettingJWTIssuer = "jwt.issuer"
// 登录注册
SettingAuthRegRequireEmail = "auth.reg.require_email"
SettingAuthRegRequirePhone = "auth.reg.require_phone"
SettingAuthLoginMethods = "auth.login.methods" // json: ["password", "email_code", "phone_code"]
SettingAuthPasswordFields = "auth.login.password_fields" // json: ["username", "email", "phone"]
// 安全/验证码
SettingSecurityBcryptCost = "security.bcrypt_cost"
SettingSecurityMaxLoginAttempts = "security.max_login_attempts"
SettingSecurityCaptchaEnabled = "security.captcha_enabled"
SettingCodeExpiry = "code.expiry" // 分钟
SettingCodeLength = "code.length"
SettingCodeMaxAttempt = "code.max_attempt"
SettingCodeSendInterval = "code.send_interval" // 秒
SettingCodeMaxDailyCount = "code.max_daily_count"
// 邮件配置
SettingEmailEnabled = "email.enabled"
SettingEmailProvider = "email.provider" // smtp/sendgrid
SettingEmailSMTPHost = "email.smtp.host"
SettingEmailSMTPPort = "email.smtp.port"
SettingEmailSMTPUser = "email.smtp.user"
SettingEmailSMTPPass = "email.smtp.pass"
SettingEmailFrom = "email.from"
SettingEmailFromName = "email.from_name"
// 短信配置
SettingSMSEnabled = "sms.enabled"
SettingSMSProvider = "sms.provider" // aliyun/tencent
SettingSMSAccessKey = "sms.access_key"
SettingSMSAccessSecret = "sms.access_secret"
SettingSMSSignName = "sms.sign_name"
SettingSMSTemplateCode = "sms.template_code"
SettingSMSEndpoint = "sms.endpoint"
)
// 默认配置值
var defaultSettings = []Setting{
// 应用
{Key: SettingAppName, Value: "VBase IAM", Type: "string", Category: SettingCategoryApp, Desc: "应用名称"},
{Key: SettingAppID, Value: "vbase", Type: "string", Category: SettingCategoryApp, Desc: "应用标识"},
// JWT
{Key: SettingJWTSecret, Value: "", Type: "string", Category: SettingCategorySecurity, Desc: "JWT密钥为空则使用本地key配置"},
{Key: SettingJWTAccessExpiry, Value: "3600", Type: "int", Category: SettingCategorySecurity, Desc: "Access Token有效期(秒)"},
{Key: SettingJWTRefreshExpiry, Value: "2592000", Type: "int", Category: SettingCategorySecurity, Desc: "Refresh Token有效期(秒)"},
{Key: SettingJWTIssuer, Value: "vbase", Type: "string", Category: SettingCategorySecurity, Desc: "JWT签发者"},
// 登录注册
{Key: SettingAuthRegRequireEmail, Value: "false", Type: "bool", Category: SettingCategoryAuth, Desc: "注册是否要求邮箱"},
{Key: SettingAuthRegRequirePhone, Value: "false", Type: "bool", Category: SettingCategoryAuth, Desc: "注册是否要求手机号"},
{Key: SettingAuthLoginMethods, Value: `["password"]`, Type: "json", Category: SettingCategoryAuth, Desc: "启用的登录方式"},
{Key: SettingAuthPasswordFields, Value: `["username"]`, Type: "json", Category: SettingCategoryAuth, Desc: "密码登录支持的身份标识"},
// 安全
{Key: SettingSecurityBcryptCost, Value: "12", Type: "int", Category: SettingCategorySecurity, Desc: "bcrypt加密强度"},
{Key: SettingSecurityMaxLoginAttempts, Value: "5", Type: "int", Category: SettingCategorySecurity, Desc: "最大登录尝试次数"},
{Key: SettingSecurityCaptchaEnabled, Value: "true", Type: "bool", Category: SettingCategorySecurity, Desc: "是否启用验证码"},
// 验证码
{Key: SettingCodeExpiry, Value: "5", Type: "int", Category: SettingCategorySecurity, Desc: "验证码有效期(分钟)"},
{Key: SettingCodeLength, Value: "6", Type: "int", Category: SettingCategorySecurity, Desc: "验证码长度"},
{Key: SettingCodeMaxAttempt, Value: "3", Type: "int", Category: SettingCategorySecurity, Desc: "验证码最大尝试次数"},
{Key: SettingCodeSendInterval, Value: "60", Type: "int", Category: SettingCategorySecurity, Desc: "发送间隔(秒)"},
{Key: SettingCodeMaxDailyCount, Value: "100", Type: "int", Category: SettingCategorySecurity, Desc: "单日最大发送次数(0禁用,-1不限制)"},
// 邮件(默认关闭)
{Key: SettingEmailEnabled, Value: "false", Type: "bool", Category: SettingCategoryEmail, Desc: "是否启用邮件服务"},
{Key: SettingEmailProvider, Value: "smtp", Type: "string", Category: SettingCategoryEmail, Desc: "邮件服务商"},
{Key: SettingEmailSMTPHost, Value: "", Type: "string", Category: SettingCategoryEmail, Desc: "SMTP服务器"},
{Key: SettingEmailSMTPPort, Value: "587", Type: "int", Category: SettingCategoryEmail, Desc: "SMTP端口"},
{Key: SettingEmailSMTPUser, Value: "", Type: "string", Category: SettingCategoryEmail, Desc: "SMTP用户名"},
{Key: SettingEmailSMTPPass, Value: "", Type: "string", Category: SettingCategoryEmail, Desc: "SMTP密码"},
{Key: SettingEmailFrom, Value: "", Type: "string", Category: SettingCategoryEmail, Desc: "发件人邮箱"},
{Key: SettingEmailFromName, Value: "VBase", Type: "string", Category: SettingCategoryEmail, Desc: "发件人显示名"},
// 短信(默认关闭)
{Key: SettingSMSEnabled, Value: "false", Type: "bool", Category: SettingCategorySMS, Desc: "是否启用短信服务"},
{Key: SettingSMSProvider, Value: "aliyun", Type: "string", Category: SettingCategorySMS, Desc: "短信服务商"},
{Key: SettingSMSAccessKey, Value: "", Type: "string", Category: SettingCategorySMS, Desc: "AccessKey ID"},
{Key: SettingSMSAccessSecret, Value: "", Type: "string", Category: SettingCategorySMS, Desc: "AccessKey Secret"},
{Key: SettingSMSSignName, Value: "", Type: "string", Category: SettingCategorySMS, Desc: "短信签名"},
{Key: SettingSMSTemplateCode, Value: "", Type: "string", Category: SettingCategorySMS, Desc: "验证码模板CODE"},
{Key: SettingSMSEndpoint, Value: "", Type: "string", Category: SettingCategorySMS, Desc: "自定义接入点"},
}
// InitSettings 初始化默认配置
func InitSettings() error {
db := cfg.DB()
for _, s := range defaultSettings {
var count int64
if err := db.Model(&Setting{}).Where("`key` = ?", s.Key).Count(&count).Error; err != nil {
return err
}
if count == 0 {
if err := db.Create(&s).Error; err != nil {
return fmt.Errorf("init setting %s failed: %w", s.Key, err)
}
}
}
return nil
}
// GetSetting 获取配置值
func GetSetting(key string) (string, error) {
var s Setting
if err := cfg.DB().Where("`key` = ?", key).First(&s).Error; err != nil {
return "", err
}
return s.Value, nil
}
// GetSettingBool 获取布尔配置
func GetSettingBool(key string) (bool, error) {
val, err := GetSetting(key)
if err != nil {
return false, err
}
return strconv.ParseBool(val)
}
// GetSettingInt 获取整数配置
func GetSettingInt(key string) (int, error) {
val, err := GetSetting(key)
if err != nil {
return 0, err
}
return strconv.Atoi(val)
}
// GetSettingJSON 获取 JSON 配置
func GetSettingJSON(key string, v interface{}) error {
val, err := GetSetting(key)
if err != nil {
return err
}
return json.Unmarshal([]byte(val), v)
}
// SetSetting 设置配置值
func SetSetting(key, value, updatedBy string) error {
var s Setting
db := cfg.DB()
if err := db.Where("`key` = ?", key).First(&s).Error; err != nil {
return err
}
s.Value = value
s.UpdatedBy = updatedBy
return db.Save(&s).Error
}