🔴 高优先级 (6项全部完成): - 数据库事务支持 (InsertMessageWithLog) - SQL注入修复 (参数化查询) - 配置验证 (Validate方法) - 会话密钥强化 (长度验证) - 签名验证增强 (SignVerificationResult) - 密码哈希支持 (bcrypt) 🟡 中优先级 (15项全部完成): - 连接池配置 (MaxOpenConns, MaxIdleConns) - 查询优化 (范围查询, 索引) - 健康检查增强 (/health 端点) - API版本控制 (/api/v1/*) - 认证中间件 (RequireAuth, RequireAPIAuth) - 定时任务优化 (robfig/cron) - 配置文件示例 (config.example.yaml) - 常量定义 (config/constants.go) - 开发文档 (DEVELOPMENT.md) 🟢 低优先级 (9项全部完成): - Docker支持 (Dockerfile, docker-compose.yml) - Makefile构建脚本 - 优化报告 (OPTIMIZATION_REPORT.md) - 密码哈希工具 (tools/password_hash.go) - 14个新文件 - 30项优化100%完成 版本: v2.0.0
143 lines
3.4 KiB
Go
143 lines
3.4 KiB
Go
package auth
|
||
|
||
import (
|
||
"encoding/hex"
|
||
"fmt"
|
||
"log"
|
||
"net/http"
|
||
"time"
|
||
|
||
"sms-receiver-go/config"
|
||
|
||
"github.com/gorilla/sessions"
|
||
)
|
||
|
||
var store *sessions.CookieStore
|
||
|
||
// SessionKey 会话相关的 key
|
||
const (
|
||
SessionKeyLoggedIn = "logged_in"
|
||
SessionKeyUsername = "username"
|
||
SessionKeyLoginTime = "login_time"
|
||
SessionKeyLastActive = "last_activity"
|
||
)
|
||
|
||
// Init 初始化会话存储
|
||
func Init(secretKey string) error {
|
||
if secretKey == "" {
|
||
return fmt.Errorf("安全密钥不能为空")
|
||
}
|
||
|
||
// 支持 hex 格式的密钥
|
||
key := []byte(secretKey)
|
||
if len(key) > 64 && len(secretKey) >= 64 { // 可能是 hex 格式 32 字节
|
||
if decodedKey, err := hex.DecodeString(secretKey); err == nil {
|
||
key = decodedKey
|
||
log.Printf("使用 hex 解码密钥")
|
||
} else {
|
||
log.Printf("hex 解码失败,使用原始密钥: %v", err)
|
||
}
|
||
}
|
||
|
||
// 检查密钥长度(至少16字节)
|
||
if len(key) < 16 {
|
||
return fmt.Errorf("安全密钥长度不足,至少需要16字节(当前: %d 字节)", len(key))
|
||
}
|
||
|
||
store = sessions.NewCookieStore(key)
|
||
store.Options = &sessions.Options{
|
||
Path: "/",
|
||
MaxAge: 86400 * 7, // 7天
|
||
HttpOnly: true,
|
||
// 不设置 SameSite,让浏览器使用默认值(Lax),在同站上下文中工作正常
|
||
// SameSite: http.SameSiteNoneMode,
|
||
// Secure: true,
|
||
}
|
||
log.Printf("会话存储初始化完成,密钥长度: %d 字节", len(key))
|
||
|
||
return nil
|
||
}
|
||
|
||
// GetStore 获取会话存储
|
||
func GetStore() *sessions.CookieStore {
|
||
return store
|
||
}
|
||
|
||
// Login 登录
|
||
func Login(w http.ResponseWriter, r *http.Request, username string) error {
|
||
session, err := store.Get(r, "sms-receiver")
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
session.Values[SessionKeyLoggedIn] = true
|
||
session.Values[SessionKeyUsername] = username
|
||
session.Values[SessionKeyLoginTime] = time.Now().Unix()
|
||
session.Values[SessionKeyLastActive] = time.Now().Unix()
|
||
|
||
return session.Save(r, w)
|
||
}
|
||
|
||
// Logout 登出
|
||
func Logout(r *http.Request, w http.ResponseWriter) error {
|
||
session, err := store.Get(r, "sms-receiver")
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
session.Values = make(map[interface{}]interface{})
|
||
session.Save(r, w)
|
||
return nil
|
||
}
|
||
|
||
// IsLoggedIn 检查是否已登录
|
||
func IsLoggedIn(r *http.Request) (bool, string) {
|
||
session, err := store.Get(r, "sms-receiver")
|
||
if err != nil {
|
||
return false, ""
|
||
}
|
||
|
||
loggedIn, ok := session.Values[SessionKeyLoggedIn].(bool)
|
||
if !ok || !loggedIn {
|
||
return false, ""
|
||
}
|
||
|
||
username, _ := session.Values[SessionKeyUsername].(string)
|
||
|
||
// 检查会话是否过期
|
||
cfg := config.Get()
|
||
if cfg != nil {
|
||
lastActive, ok := session.Values[SessionKeyLastActive].(int64)
|
||
if ok {
|
||
sessionLifetime := cfg.GetSessionLifetimeDuration()
|
||
if time.Now().Unix()-lastActive > int64(sessionLifetime.Seconds()) {
|
||
return false, ""
|
||
}
|
||
// 更新最后活跃时间
|
||
session.Values[SessionKeyLastActive] = time.Now().Unix()
|
||
}
|
||
}
|
||
|
||
return true, username
|
||
}
|
||
|
||
// CheckLogin 检查登录状态,未登录则跳转到登录页
|
||
func CheckLogin(w http.ResponseWriter, r *http.Request) (bool, string) {
|
||
loggedIn, username := IsLoggedIn(r)
|
||
if !loggedIn {
|
||
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
||
return false, ""
|
||
}
|
||
return true, username
|
||
}
|
||
|
||
// GetCurrentUser 获取当前用户名
|
||
func GetCurrentUser(r *http.Request) string {
|
||
session, err := store.Get(r, "sms-receiver")
|
||
if err != nil {
|
||
return ""
|
||
}
|
||
username, _ := session.Values[SessionKeyUsername].(string)
|
||
return username
|
||
}
|