feat: add email verification and password reset functionality

- Introduced environment variables for database and email configurations.
- Implemented email verification code generation and validation.
- Added password reset feature with email verification.
- Updated user registration and profile management APIs.
- Refactored user security settings to include email and password updates.
- Enhanced console layout with internationalization support.
- Removed deprecated settings page and integrated global settings.
- Added new reset password page and form components.
- Updated localization files for new features and translations.
This commit is contained in:
2025-09-23 00:33:34 +08:00
parent c9db6795b2
commit b0b32c93d1
32 changed files with 888 additions and 345 deletions

View File

@ -19,6 +19,23 @@ const (
EnvKeyCaptchaSecreteKey = "CAPTCHA_SECRET_KEY" // captcha站点密钥
EnvKeyCaptchaUrl = "CAPTCHA_URL" // 某些自托管的captcha的url
EnvKeyCaptchaSiteKey = "CAPTCHA_SITE_KEY" // captcha密钥key
EnvKeyDBDriver = "DB_DRIVER" // 环境变量:数据库驱动
EnvKeyDBPath = "DB_PATH" // 环境变量数据库文件路径仅适用于SQLite
EnvKeyDBHost = "DB_HOST" // 环境变量数据库主机仅适用于PostgreSQL
EnvKeyDBPort = "DB_PORT" // 环境变量数据库端口仅适用于PostgreSQL
EnvKeyDBUser = "DB_USER" // 环境变量数据库用户仅适用于PostgreSQL
EnvKeyDBPassword = "DB_PASSWORD" // 环境变量数据库密码仅适用于PostgreSQL
EnvKeyDBName = "DB_NAME" // 环境变量数据库名称仅适用于PostgreSQL
EnvKeyDBSSLMode = "DB_SSLMODE" // 环境变量数据库SSL模式仅适用于PostgreSQL
EnvKeyEmailAddress = "EMAIL_ADDRESS"
EnvKeyEmailEnable = "EMAIL_ENABLE"
EnvKeyEmailHost = "EMAIL_HOST"
EnvKeyEmailPort = "EMAIL_PORT"
EnvKeyEmailUsername = "EMAIL_USERNAME"
EnvKeyEmailPassword = "EMAIL_PASSWORD"
EnvKeyEmailSsl = "EMAIL_SSL"
EnvKeyEnableRegister = "ENABLE_REGISTER"
EnvKeyEnableEmailVerify = "ENABLE_EMAIL_VERIFY"
EnvKeyFileDriverType = "FILE_DRIVER_TYPE"
EnvKeyFileBasepath = "FILE_BASEPATH"
EnvKeyFileWebdavUrl = "FILE_WEBDAV_URL"
@ -39,6 +56,8 @@ const (
FileDriverTypeLocal = "local"
FileDriverTypeWebdav = "webdav"
FileDriverTypeS3 = "s3"
HeaderKeyEmail = "X-Email"
HeaderKeyVerifyCode = "X-VerifyCode"
KVKeyEmailVerificationCode = "email_verification_code:" // KV存储邮箱验证码
KVKeyOidcState = "oidc_state:" // KV存储OIDC状态
ApiSuffix = "/api/v1" // API版本前缀
@ -46,6 +65,7 @@ const (
OidcProviderTypeMisskey = "misskey" // OIDC提供者类型Misskey
OidcProviderTypeOauth2 = "oauth2" // OIDC提供者类型GitHub
DefaultBaseUrl = "http://localhost:3000" // 默认BaseUrl
DefaultPasswordSalt = "default_salt_114514"
TargetTypePost = "post"
TargetTypeComment = "comment"
WebdavPolicyProxy = "proxy"

View File

@ -3,9 +3,12 @@ package utils
import (
"bytes"
"crypto/tls"
"errors"
"fmt"
"gopkg.in/gomail.v2"
"html/template"
"github.com/snowykami/neo-blog/pkg/constant"
"gopkg.in/gomail.v2"
)
type emailUtils struct{}
@ -42,7 +45,7 @@ func (e *emailUtils) SendTemplate(emailConfig *EmailConfig, target, subject, htm
// SendEmail 使用gomail库发送邮件
func (e *emailUtils) SendEmail(emailConfig *EmailConfig, target, subject, content string, isHTML bool) error {
if !emailConfig.Enable {
return nil
return errors.New("邮箱服务未启用")
}
// 创建新邮件
m := gomail.NewMessage()
@ -73,12 +76,12 @@ func (e *emailUtils) SendEmail(emailConfig *EmailConfig, target, subject, conten
func (e *emailUtils) GetEmailConfigFromEnv() *EmailConfig {
return &EmailConfig{
Enable: Env.GetAsBool("EMAIL_ENABLE", false),
Username: Env.Get("EMAIL_USERNAME", ""),
Address: Env.Get("EMAIL_ADDRESS", ""),
Host: Env.Get("EMAIL_HOST", "smtp.example.com"),
Port: Env.GetAsInt("EMAIL_PORT", 587),
Password: Env.Get("EMAIL_PASSWORD", ""),
SSL: Env.GetAsBool("EMAIL_SSL", true),
Enable: Env.GetAsBool(constant.EnvKeyEmailEnable, false),
Username: Env.Get(constant.EnvKeyEmailUsername, ""),
Address: Env.Get(constant.EnvKeyEmailAddress, ""),
Host: Env.Get(constant.EnvKeyEmailHost, "smtp.example.com"),
Port: Env.GetAsInt(constant.EnvKeyEmailPort, 587),
Password: Env.Get(constant.EnvKeyEmailPassword, ""),
SSL: Env.GetAsBool(constant.EnvKeyEmailSsl, true),
}
}

View File

@ -1 +1,27 @@
package utils
import (
"time"
"github.com/snowykami/neo-blog/pkg/constant"
)
func RequestEmailVerify(email string) string {
generatedVerificationCode := Strings.GenerateRandomStringWithCharset(6, "0123456789abcdef")
kv := KV.GetInstance()
kv.Set(constant.KVKeyEmailVerificationCode+email, generatedVerificationCode, time.Minute*10)
return generatedVerificationCode
}
func VerifyEmailCode(email, code string) bool {
kv := KV.GetInstance()
storedCode, ok := kv.Get(constant.KVKeyEmailVerificationCode + email)
if !ok {
return false
}
if storedCode != code {
return false
}
kv.Delete(constant.KVKeyEmailVerificationCode + email)
return true
}

View File

@ -3,6 +3,7 @@ package utils
import (
"crypto/sha256"
"encoding/hex"
"golang.org/x/crypto/bcrypt"
)