diff --git a/internal/auth/handler.go b/internal/auth/handler.go index 7fbcba2..ba18f4c 100644 --- a/internal/auth/handler.go +++ b/internal/auth/handler.go @@ -81,6 +81,25 @@ func (h *Handler) UpdateRole(c *fiber.Ctx) error { return c.JSON(fiber.Map{"message": "권한이 변경되었습니다"}) } +func (h *Handler) VerifyToken(c *fiber.Ctx) error { + var req struct { + Token string `json:"token"` + } + if err := c.BodyParser(&req); err != nil || req.Token == "" { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "token 필드가 필요합니다"}) + } + + userID, username, err := h.svc.VerifyToken(req.Token) + if err != nil { + return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": err.Error()}) + } + + return c.JSON(fiber.Map{ + "userId": userID, + "username": username, + }) +} + func (h *Handler) DeleteUser(c *fiber.Ctx) error { if err := h.svc.DeleteUser(c.Params("id")); err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "유저 삭제에 실패했습니다"}) diff --git a/internal/auth/service.go b/internal/auth/service.go index 6389d63..5cd6053 100644 --- a/internal/auth/service.go +++ b/internal/auth/service.go @@ -92,6 +92,32 @@ func (s *Service) Register(username, password string) error { }) } +// VerifyToken validates a JWT and its Redis session, returning (userID, username, error). +func (s *Service) VerifyToken(tokenStr string) (uint, string, error) { + token, err := jwt.ParseWithClaims(tokenStr, &Claims{}, func(t *jwt.Token) (any, error) { + if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("unexpected signing method") + } + return []byte(config.C.JWTSecret), nil + }) + if err != nil || !token.Valid { + return 0, "", fmt.Errorf("유효하지 않은 토큰입니다") + } + + claims, ok := token.Claims.(*Claims) + if !ok { + return 0, "", fmt.Errorf("토큰 파싱 실패") + } + + key := fmt.Sprintf("session:%d", claims.UserID) + stored, err := s.rdb.Get(context.Background(), key).Result() + if err != nil || stored != tokenStr { + return 0, "", fmt.Errorf("만료되었거나 로그아웃된 세션입니다") + } + + return claims.UserID, claims.Username, nil +} + func (s *Service) EnsureAdmin(username, password string) error { if _, err := s.repo.FindByUsername(username); err == nil { return nil // 이미 존재하면 스킵 diff --git a/routes/routes.go b/routes/routes.go index 85ee43e..10f8a19 100644 --- a/routes/routes.go +++ b/routes/routes.go @@ -21,6 +21,7 @@ func Register( a.Post("/register", authH.Register) a.Post("/login", authH.Login) a.Post("/logout", middleware.Auth, authH.Logout) + a.Post("/verify", authH.VerifyToken) // Users (admin only) u := api.Group("/users", middleware.Auth, middleware.AdminOnly)