wood chen e89ef02205 特性(代理):通过端口和身份验证更新来增强服务器配置和安全性。
- 更新 docker-compose.yml 文件,使用端口 3336
- 修改 Dockerfile 以暴露端口 3336
- 重构 main.go 以支持新的路由和管理端点
- 在 auth.go 中实现健壮的身份验证中间件
- 通过加强错误检查来改进指标处理。
- 添加用于安全类型转换的实用函数
- 引入请求ID生成功能,以便更好地进行追踪。
2025-02-15 08:07:28 +08:00

114 lines
2.5 KiB
Go

package handler
import (
"crypto/rand"
"encoding/base64"
"encoding/json"
"net/http"
"strings"
"sync"
"time"
)
type tokenInfo struct {
createdAt time.Time
expiresIn time.Duration
}
type authManager struct {
tokens sync.Map
}
func newAuthManager() *authManager {
am := &authManager{}
// 启动token清理goroutine
go am.cleanExpiredTokens()
return am
}
func (am *authManager) generateToken() string {
b := make([]byte, 32)
rand.Read(b)
return base64.URLEncoding.EncodeToString(b)
}
func (am *authManager) addToken(token string, expiry time.Duration) {
am.tokens.Store(token, tokenInfo{
createdAt: time.Now(),
expiresIn: expiry,
})
}
func (am *authManager) validateToken(token string) bool {
if info, ok := am.tokens.Load(token); ok {
tokenInfo := info.(tokenInfo)
if time.Since(tokenInfo.createdAt) < tokenInfo.expiresIn {
return true
}
am.tokens.Delete(token)
}
return false
}
func (am *authManager) cleanExpiredTokens() {
ticker := time.NewTicker(time.Hour)
for range ticker.C {
am.tokens.Range(func(key, value interface{}) bool {
token := key.(string)
info := value.(tokenInfo)
if time.Since(info.createdAt) >= info.expiresIn {
am.tokens.Delete(token)
}
return true
})
}
}
// AuthMiddleware 认证中间件
func (h *ProxyHandler) AuthMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
auth := r.Header.Get("Authorization")
if auth == "" || !strings.HasPrefix(auth, "Bearer ") {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
token := strings.TrimPrefix(auth, "Bearer ")
if !h.auth.validateToken(token) {
http.Error(w, "Invalid token", http.StatusUnauthorized)
return
}
next(w, r)
}
}
// AuthHandler 处理认证请求
func (h *ProxyHandler) AuthHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
var req struct {
Password string `json:"password"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid request", http.StatusBadRequest)
return
}
if req.Password != h.config.Metrics.Password {
http.Error(w, "Invalid password", http.StatusUnauthorized)
return
}
token := h.auth.generateToken()
h.auth.addToken(token, time.Duration(h.config.Metrics.TokenExpiry)*time.Second)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{
"token": token,
})
}