Some checks failed
Build Multi-Platform Binaries / build-frontend (push) Successful in 30s
Build Multi-Platform Binaries / build-binaries (amd64, darwin, server, false) (push) Successful in 1m4s
Build Multi-Platform Binaries / build-binaries (amd64, linux, client, true) (push) Successful in 45s
Build Multi-Platform Binaries / build-binaries (amd64, linux, server, true) (push) Successful in 1m29s
Build Multi-Platform Binaries / build-binaries (amd64, windows, client, true) (push) Successful in 45s
Build Multi-Platform Binaries / build-binaries (amd64, windows, server, true) (push) Successful in 1m27s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, client, true) (push) Successful in 50s
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) Has been cancelled
Build Multi-Platform Binaries / build-binaries (arm64, linux, client, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (arm64, linux, server, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (arm64, windows, server, false) (push) Has been cancelled
101 lines
2.5 KiB
Go
101 lines
2.5 KiB
Go
package handler
|
|
|
|
import (
|
|
"crypto/subtle"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
// removed router import
|
|
"github.com/gotunnel/internal/server/router/dto"
|
|
"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,
|
|
}
|
|
}
|
|
|
|
// Login 用户登录
|
|
// @Summary 用户登录
|
|
// @Description 使用用户名密码登录,返回 JWT token
|
|
// @Tags 认证
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body dto.LoginRequest true "登录信息"
|
|
// @Success 200 {object} Response{data=dto.LoginResponse}
|
|
// @Failure 400 {object} Response
|
|
// @Failure 401 {object} Response
|
|
// @Router /api/auth/login [post]
|
|
func (h *AuthHandler) Login(c *gin.Context) {
|
|
var req dto.LoginRequest
|
|
if !BindJSON(c, &req) {
|
|
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(c.ClientIP(), req.Username, false)
|
|
Unauthorized(c, "invalid credentials")
|
|
return
|
|
}
|
|
|
|
// 生成 token
|
|
token, err := h.jwtAuth.GenerateToken(req.Username)
|
|
if err != nil {
|
|
InternalError(c, "failed to generate token")
|
|
return
|
|
}
|
|
|
|
security.LogWebLogin(c.ClientIP(), req.Username, true)
|
|
Success(c, dto.LoginResponse{Token: token})
|
|
}
|
|
|
|
// Check 检查 token 是否有效
|
|
// @Summary 检查 Token
|
|
// @Description 验证 JWT token 是否有效
|
|
// @Tags 认证
|
|
// @Produce json
|
|
// @Security Bearer
|
|
// @Success 200 {object} Response{data=dto.TokenCheckResponse}
|
|
// @Failure 401 {object} Response
|
|
// @Router /api/auth/check [get]
|
|
func (h *AuthHandler) Check(c *gin.Context) {
|
|
authHeader := c.GetHeader("Authorization")
|
|
if authHeader == "" {
|
|
Unauthorized(c, "missing authorization header")
|
|
return
|
|
}
|
|
|
|
const prefix = "Bearer "
|
|
if len(authHeader) < len(prefix) || authHeader[:len(prefix)] != prefix {
|
|
Unauthorized(c, "invalid authorization format")
|
|
return
|
|
}
|
|
tokenStr := authHeader[len(prefix):]
|
|
|
|
claims, err := h.jwtAuth.ValidateToken(tokenStr)
|
|
if err != nil {
|
|
Unauthorized(c, "invalid token")
|
|
return
|
|
}
|
|
|
|
Success(c, dto.TokenCheckResponse{
|
|
Valid: true,
|
|
Username: claims.Username,
|
|
})
|
|
}
|