Files
SmsReceiver-go/auth/auth.go
OpenClaw Agent 1da899a0f4 feat: v2.0.0 完整代码优化升级
🔴 高优先级 (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
2026-02-08 18:59:29 +08:00

143 lines
3.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}