Feat: Enable admin password in admin mode (#540)

* WIP: save local changes before merging
* Enable admin password in admin mode #374
This commit is contained in:
Burt
2025-11-05 21:48:28 +08:00
committed by GitHub
parent 96ed2c6ea7
commit 8b853a963d
13 changed files with 421 additions and 91 deletions
+67
View File
@@ -3,6 +3,8 @@ package auth
import (
"crypto/rand"
"fmt"
"log"
"sync"
"time"
"github.com/golang-jwt/jwt/v5"
@@ -17,6 +19,18 @@ var JWTSecret []byte
// AdminMode 管理员模式标志
var AdminMode bool = false
// adminPasswordHash 管理员密码哈希(仅内存)
var adminPasswordHash string
// tokenBlacklist 用于登出后的token黑名单(仅内存,按过期时间清理)
var tokenBlacklist = struct {
sync.RWMutex
items map[string]time.Time
}{items: make(map[string]time.Time)}
// maxBlacklistEntries 黑名单最大容量阈值
const maxBlacklistEntries = 100_000
// OTPIssuer OTP发行者名称
const OTPIssuer = "nofxAI"
@@ -35,6 +49,59 @@ func IsAdminMode() bool {
return AdminMode
}
// SetAdminPasswordFromPlain 通过明文设置管理员密码(会使用bcrypt哈希,成本12)
func SetAdminPasswordFromPlain(plain string) error {
bytes, err := bcrypt.GenerateFromPassword([]byte(plain), 12)
if err != nil {
return err
}
adminPasswordHash = string(bytes)
return nil
}
// CheckAdminPassword 校验管理员密码
func CheckAdminPassword(plain string) bool {
if adminPasswordHash == "" {
return false
}
return bcrypt.CompareHashAndPassword([]byte(adminPasswordHash), []byte(plain)) == nil
}
// BlacklistToken 将token加入黑名单直到过期
func BlacklistToken(token string, exp time.Time) {
tokenBlacklist.Lock()
defer tokenBlacklist.Unlock()
tokenBlacklist.items[token] = exp
// 如果超过容量阈值,则进行一次过期清理;若仍超限,记录警告日志
if len(tokenBlacklist.items) > maxBlacklistEntries {
now := time.Now()
for t, e := range tokenBlacklist.items {
if now.After(e) {
delete(tokenBlacklist.items, t)
}
}
if len(tokenBlacklist.items) > maxBlacklistEntries {
log.Printf("auth: token blacklist size (%d) exceeds limit (%d) after sweep; consider reducing JWT TTL or using a shared persistent store",
len(tokenBlacklist.items), maxBlacklistEntries)
}
}
}
// IsTokenBlacklisted 检查token是否在黑名单中(过期自动清理)
func IsTokenBlacklisted(token string) bool {
tokenBlacklist.Lock()
defer tokenBlacklist.Unlock()
if exp, ok := tokenBlacklist.items[token]; ok {
if time.Now().After(exp) {
delete(tokenBlacklist.items, token)
return false
}
return true
}
return false
}
// Claims JWT声明
type Claims struct {
UserID string `json:"user_id"`