2026-03-06 16:39:42 +08:00
|
|
|
|
package handler
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"net/http"
|
2026-03-11 14:25:55 +08:00
|
|
|
|
"strings"
|
2026-03-06 16:39:42 +08:00
|
|
|
|
|
|
|
|
|
|
"x-agents/server/internal/service"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2026-03-11 14:25:55 +08:00
|
|
|
|
// maskEmail 邮箱脱敏,只显示前后各1个字符
|
|
|
|
|
|
func maskEmail(email string) string {
|
|
|
|
|
|
if email == "" {
|
|
|
|
|
|
return ""
|
|
|
|
|
|
}
|
|
|
|
|
|
parts := strings.Split(email, "@")
|
|
|
|
|
|
if len(parts) != 2 {
|
|
|
|
|
|
return "***"
|
|
|
|
|
|
}
|
|
|
|
|
|
local := parts[0]
|
|
|
|
|
|
domain := parts[1]
|
|
|
|
|
|
if len(local) <= 2 {
|
|
|
|
|
|
local = "**"
|
|
|
|
|
|
} else {
|
|
|
|
|
|
local = string(local[0]) + "***" + string(local[len(local)-1])
|
|
|
|
|
|
}
|
|
|
|
|
|
if len(domain) <= 2 {
|
|
|
|
|
|
domain = "***"
|
|
|
|
|
|
} else {
|
|
|
|
|
|
domain = string(domain[0]) + "***" + string(domain[len(domain)-1])
|
|
|
|
|
|
}
|
|
|
|
|
|
return local + "@" + domain
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// @title X-Agents API
|
|
|
|
|
|
// @version 1.0
|
|
|
|
|
|
// @description X-Agents 后端 API 文档
|
|
|
|
|
|
// @termsOfService http://swagger.io/terms/
|
|
|
|
|
|
|
|
|
|
|
|
// @contact.name API Support
|
|
|
|
|
|
// @contact.url http://www.example.com/support
|
|
|
|
|
|
// @contact.email support@example.com
|
|
|
|
|
|
|
|
|
|
|
|
// @license.name Apache 2.0
|
|
|
|
|
|
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
|
|
|
|
|
|
|
|
|
|
|
|
// @host localhost:8080
|
|
|
|
|
|
// @BasePath /
|
|
|
|
|
|
|
|
|
|
|
|
// @securityDefinitions.apikey BearerAuth
|
|
|
|
|
|
// @in header
|
|
|
|
|
|
// @name Authorization
|
|
|
|
|
|
// @description Type "Bearer" followed by a space and JWT token.
|
|
|
|
|
|
|
2026-03-06 16:39:42 +08:00
|
|
|
|
type AuthHandler struct {
|
|
|
|
|
|
authService *service.AuthService
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func NewAuthHandler(authService *service.AuthService) *AuthHandler {
|
|
|
|
|
|
return &AuthHandler{authService: authService}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type LoginRequest struct {
|
|
|
|
|
|
Username string `json:"username" binding:"required"`
|
|
|
|
|
|
Password string `json:"password" binding:"required"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type LoginResponse struct {
|
|
|
|
|
|
Token string `json:"token"`
|
|
|
|
|
|
User interface{} `json:"user"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-11 14:25:55 +08:00
|
|
|
|
// RegisterRequest 注册请求
|
|
|
|
|
|
type RegisterRequest struct {
|
|
|
|
|
|
Username string `json:"username" binding:"required"`
|
|
|
|
|
|
Password string `json:"password" binding:"required"`
|
|
|
|
|
|
Email string `json:"email"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// @Summary 用户登录
|
|
|
|
|
|
// @Description 用户登录并获取 JWT Token
|
|
|
|
|
|
// @Tags 认证
|
|
|
|
|
|
// @Accept json
|
|
|
|
|
|
// @Produce json
|
|
|
|
|
|
// @Param request body LoginRequest true "登录请求"
|
|
|
|
|
|
// @Success 200 {object} LoginResponse
|
|
|
|
|
|
// @Failure 400 {object} map[string]string
|
|
|
|
|
|
// @Failure 401 {object} map[string]string
|
|
|
|
|
|
// @Router /auth/login [post]
|
2026-03-06 16:39:42 +08:00
|
|
|
|
func (h *AuthHandler) Login(c *gin.Context) {
|
|
|
|
|
|
var req LoginRequest
|
|
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
resp, err := h.authService.Login(service.LoginRequest{
|
|
|
|
|
|
Username: req.Username,
|
|
|
|
|
|
Password: req.Password,
|
|
|
|
|
|
})
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
c.JSON(http.StatusOK, LoginResponse{
|
|
|
|
|
|
Token: resp.Token,
|
|
|
|
|
|
User: gin.H{
|
|
|
|
|
|
"id": resp.User.ID,
|
|
|
|
|
|
"username": resp.User.Username,
|
|
|
|
|
|
"email": resp.User.Email,
|
|
|
|
|
|
"role": resp.User.RoleID,
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-11 14:25:55 +08:00
|
|
|
|
// @Summary 用户注册
|
|
|
|
|
|
// @Description 新用户注册账号
|
|
|
|
|
|
// @Tags 认证
|
|
|
|
|
|
// @Accept json
|
|
|
|
|
|
// @Produce json
|
|
|
|
|
|
// @Param RegisterRequest body handler.RegisterRequest true "注册请求"
|
|
|
|
|
|
// @Success 201 {object} map[string]interface{}
|
|
|
|
|
|
// @Failure 400 {object} map[string]string
|
|
|
|
|
|
// @Router /auth/register [post]
|
2026-03-06 16:39:42 +08:00
|
|
|
|
func (h *AuthHandler) Register(c *gin.Context) {
|
2026-03-11 14:25:55 +08:00
|
|
|
|
var req RegisterRequest
|
2026-03-06 16:39:42 +08:00
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
user, err := h.authService.Register(req.Username, req.Password, req.Email)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
c.JSON(http.StatusCreated, gin.H{
|
|
|
|
|
|
"id": user.ID,
|
|
|
|
|
|
"username": user.Username,
|
2026-03-11 14:25:55 +08:00
|
|
|
|
"email": maskEmail(user.Email),
|
2026-03-06 16:39:42 +08:00
|
|
|
|
})
|
|
|
|
|
|
}
|
2026-03-11 10:25:50 +08:00
|
|
|
|
|
2026-03-11 14:25:55 +08:00
|
|
|
|
// @Summary 获取当前用户信息
|
|
|
|
|
|
// @Description 获取已登录用户的详细信息
|
|
|
|
|
|
// @Tags 认证
|
|
|
|
|
|
// @Accept json
|
|
|
|
|
|
// @Produce json
|
|
|
|
|
|
// @Security BearerAuth
|
|
|
|
|
|
// @Success 200 {object} map[string]interface{}
|
|
|
|
|
|
// @Failure 401 {object} map[string]string
|
|
|
|
|
|
// @Router /auth/me [get]
|
2026-03-11 10:25:50 +08:00
|
|
|
|
func (h *AuthHandler) GetCurrentUser(c *gin.Context) {
|
|
|
|
|
|
userID, exists := c.Get("user_id")
|
|
|
|
|
|
if !exists {
|
|
|
|
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "user not found in context"})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
user, err := h.authService.GetUserByID(userID.(string))
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
|
|
|
|
"id": user.ID,
|
|
|
|
|
|
"username": user.Username,
|
2026-03-11 14:25:55 +08:00
|
|
|
|
"email": maskEmail(user.Email),
|
2026-03-11 10:25:50 +08:00
|
|
|
|
"role_id": user.RoleID,
|
|
|
|
|
|
"is_active": user.IsActive,
|
|
|
|
|
|
"created_at": user.CreatedAt,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2026-03-11 14:25:55 +08:00
|
|
|
|
|
|
|
|
|
|
// @Summary 获取所有用户
|
|
|
|
|
|
// @Description 获取所有用户列表(需要管理员权限)
|
|
|
|
|
|
// @Tags 用户管理
|
|
|
|
|
|
// @Accept json
|
|
|
|
|
|
// @Produce json
|
|
|
|
|
|
// @Security BearerAuth
|
|
|
|
|
|
// @Success 200 {object} map[string]interface{}
|
|
|
|
|
|
// @Failure 401 {object} map[string]string
|
|
|
|
|
|
// @Router /user/list [get]
|
|
|
|
|
|
func (h *AuthHandler) ListUsers(c *gin.Context) {
|
|
|
|
|
|
users, err := h.authService.GetAllUsers()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var userList []gin.H
|
|
|
|
|
|
for _, user := range users {
|
|
|
|
|
|
userList = append(userList, gin.H{
|
|
|
|
|
|
"id": user.ID,
|
|
|
|
|
|
"username": user.Username,
|
|
|
|
|
|
"email": maskEmail(user.Email),
|
|
|
|
|
|
"role_id": user.RoleID,
|
|
|
|
|
|
"is_active": user.IsActive,
|
|
|
|
|
|
"created_at": user.CreatedAt,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
c.JSON(http.StatusOK, gin.H{"list": userList})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// @Summary 获取用户详情
|
|
|
|
|
|
// @Description 根据ID获取用户详情
|
|
|
|
|
|
// @Tags 用户管理
|
|
|
|
|
|
// @Accept json
|
|
|
|
|
|
// @Produce json
|
|
|
|
|
|
// @Security BearerAuth
|
|
|
|
|
|
// @Param id path string true "用户ID"
|
|
|
|
|
|
// @Success 200 {object} map[string]interface{}
|
|
|
|
|
|
// @Failure 404 {object} map[string]string
|
|
|
|
|
|
// @Router /user/{id} [get]
|
|
|
|
|
|
func (h *AuthHandler) GetUserByID(c *gin.Context) {
|
|
|
|
|
|
id := c.Param("id")
|
|
|
|
|
|
if id == "" {
|
|
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "user id is required"})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
user, err := h.authService.GetUserByID(id)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
|
|
|
|
"id": user.ID,
|
|
|
|
|
|
"username": user.Username,
|
|
|
|
|
|
"email": maskEmail(user.Email),
|
|
|
|
|
|
"role_id": user.RoleID,
|
|
|
|
|
|
"is_active": user.IsActive,
|
|
|
|
|
|
"created_at": user.CreatedAt,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|