Files
GoTunnel/internal/server/router/auth.go
Flik 4d2a2a7117
All checks were successful
Build Multi-Platform Binaries / build-frontend (push) Successful in 30s
Build Multi-Platform Binaries / build-binaries (amd64, darwin, server, false) (push) Successful in 58s
Build Multi-Platform Binaries / build-binaries (amd64, linux, client, true) (push) Successful in 48s
Build Multi-Platform Binaries / build-binaries (amd64, linux, server, true) (push) Successful in 1m23s
Build Multi-Platform Binaries / build-binaries (amd64, windows, client, true) (push) Successful in 56s
Build Multi-Platform Binaries / build-binaries (amd64, windows, server, true) (push) Successful in 58s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, client, true) (push) Successful in 52s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, server, true) (push) Successful in 1m42s
Build Multi-Platform Binaries / build-binaries (arm64, darwin, server, false) (push) Successful in 1m19s
Build Multi-Platform Binaries / build-binaries (arm64, linux, client, true) (push) Successful in 54s
Build Multi-Platform Binaries / build-binaries (arm64, linux, server, true) (push) Successful in 2m3s
Build Multi-Platform Binaries / build-binaries (arm64, windows, server, false) (push) Successful in 1m1s
update
2025-12-29 23:08:15 +08:00

109 lines
2.9 KiB
Go

package router
import (
"crypto/subtle"
"encoding/json"
"net/http"
"github.com/gotunnel/pkg/auth"
"github.com/gotunnel/pkg/security"
)
// AuthHandler 认证处理器
type AuthHandler struct {
username string
password string
jwtAuth *auth.JWTAuth
}
// NewAuthHandler 创建认证处理器
func NewAuthHandler(username, password string, jwtAuth *auth.JWTAuth) *AuthHandler {
return &AuthHandler{
username: username,
password: password,
jwtAuth: jwtAuth,
}
}
// RegisterAuthRoutes 注册认证路由
func RegisterAuthRoutes(r *Router, h *AuthHandler) {
r.HandleFunc("/api/auth/login", h.handleLogin)
r.HandleFunc("/api/auth/check", h.handleCheck)
}
// handleLogin 处理登录请求
func (h *AuthHandler) handleLogin(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed)
return
}
var req struct {
Username string `json:"username"`
Password string `json:"password"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
return
}
// 验证用户名密码
userMatch := subtle.ConstantTimeCompare([]byte(req.Username), []byte(h.username)) == 1
passMatch := subtle.ConstantTimeCompare([]byte(req.Password), []byte(h.password)) == 1
if !userMatch || !passMatch {
security.LogWebLogin(r.RemoteAddr, req.Username, false)
http.Error(w, `{"error":"invalid credentials"}`, http.StatusUnauthorized)
return
}
// 生成 token
token, err := h.jwtAuth.GenerateToken(req.Username)
if err != nil {
http.Error(w, `{"error":"failed to generate token"}`, http.StatusInternalServerError)
return
}
security.LogWebLogin(r.RemoteAddr, req.Username, true)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{
"token": token,
})
}
// handleCheck 检查 token 是否有效
func (h *AuthHandler) handleCheck(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed)
return
}
// 从 Authorization header 获取 token
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
http.Error(w, `{"error":"missing authorization header"}`, http.StatusUnauthorized)
return
}
// 解析 Bearer token
const prefix = "Bearer "
if len(authHeader) < len(prefix) || authHeader[:len(prefix)] != prefix {
http.Error(w, `{"error":"invalid authorization format"}`, http.StatusUnauthorized)
return
}
tokenStr := authHeader[len(prefix):]
// 验证 token
claims, err := h.jwtAuth.ValidateToken(tokenStr)
if err != nil {
http.Error(w, `{"error":"invalid token"}`, http.StatusUnauthorized)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
"valid": true,
"username": claims.Username,
})
}