From 2b794f97a36bbcfd311e4cce8722f2291385fddb Mon Sep 17 00:00:00 2001 From: d3m0k1d Date: Sat, 14 Feb 2026 21:51:44 +0300 Subject: [PATCH] feat: add validator for jwt --- backend/docs/docs.go | 30 +++++++++ backend/docs/swagger.json | 30 +++++++++ backend/docs/swagger.yaml | 20 ++++++ backend/internal/auth/jwt.go | 67 +++++++++++++++++-- backend/internal/handlers/auth_handlers.go | 41 +++++++++++- .../internal/handlers/registry_handlers.go | 1 + 6 files changed, 183 insertions(+), 6 deletions(-) diff --git a/backend/docs/docs.go b/backend/docs/docs.go index 72722c0..70aaa57 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -382,6 +382,36 @@ const docTemplate = `{ } } } + }, + "/session": { + "get": { + "description": "Returns user session data", + "produces": [ + "application/json" + ], + "tags": [ + "auth" + ], + "summary": "Get user session", + "responses": { + "200": { + "description": "Session data", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } } }, "definitions": { diff --git a/backend/docs/swagger.json b/backend/docs/swagger.json index f5d0888..86967b0 100644 --- a/backend/docs/swagger.json +++ b/backend/docs/swagger.json @@ -371,6 +371,36 @@ } } } + }, + "/session": { + "get": { + "description": "Returns user session data", + "produces": [ + "application/json" + ], + "tags": [ + "auth" + ], + "summary": "Get user session", + "responses": { + "200": { + "description": "Session data", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } } }, "definitions": { diff --git a/backend/docs/swagger.yaml b/backend/docs/swagger.yaml index 4bf796a..6bbafa1 100644 --- a/backend/docs/swagger.yaml +++ b/backend/docs/swagger.yaml @@ -272,6 +272,26 @@ paths: summary: Update post tags: - posts + /session: + get: + description: Returns user session data + produces: + - application/json + responses: + "200": + description: Session data + schema: + additionalProperties: true + type: object + "401": + description: Unauthorized + schema: + additionalProperties: + type: string + type: object + summary: Get user session + tags: + - auth securityDefinitions: Bearer: description: Type "Bearer" followed by a space and the JWT token. diff --git a/backend/internal/auth/jwt.go b/backend/internal/auth/jwt.go index 6a60f9f..7a5fab5 100644 --- a/backend/internal/auth/jwt.go +++ b/backend/internal/auth/jwt.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "strings" + "time" "gitea.d3m0k1d.ru/d3m0k1d/d3m0k1d.ru/backend/internal/storage" "github.com/gin-gonic/gin" @@ -14,10 +15,13 @@ var jwtSecret = []byte(os.Getenv("JWT_SECRET")) func GenerateJWT(user storage.User) (string, error) { token := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{ - "id": user.ID, - "email": user.Email, - "login": user.GithubLogin, - "github_id": user.GithubID, + "id": user.ID, + "email": user.Email, + "login": user.GithubLogin, + "github_id": user.GithubID, + "avatar_url": user.AvatarURL, + "exp": time.Now().Add(30 * 24 * time.Hour).Unix(), // 30 дней + "iat": time.Now().Unix(), }) tokenString, err := token.SignedString(jwtSecret) if err != nil { @@ -113,3 +117,58 @@ func RequireAdmin() gin.HandlerFunc { c.Next() } } + +func ValidateJWT(tokenString string) (*storage.User, error) { + token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) + } + return jwtSecret, nil + }) + + if err != nil || !token.Valid { + return nil, err + } + + claims, ok := token.Claims.(jwt.MapClaims) + if !ok { + return nil, fmt.Errorf("invalid claims") + } + + if exp, ok := claims["exp"].(float64); ok { + if time.Now().Unix() > int64(exp) { + return nil, fmt.Errorf("token expired") + } + } + idFloat, ok := claims["id"].(float64) + if !ok { + return nil, fmt.Errorf("invalid id in token") + } + + githubIDFloat, ok := claims["github_id"].(float64) + if !ok { + return nil, fmt.Errorf("invalid github_id in token") + } + + login, ok := claims["login"].(string) + if !ok { + return nil, fmt.Errorf("invalid login in token") + } + + email, ok := claims["email"].(string) + if !ok { + return nil, fmt.Errorf("invalid email in token") + } + + avatarURL, _ := claims["avatar_url"].(string) + + user := &storage.User{ + ID: int(idFloat), + GithubID: int(githubIDFloat), + GithubLogin: login, + Email: email, + AvatarURL: avatarURL, + } + + return user, nil +} diff --git a/backend/internal/handlers/auth_handlers.go b/backend/internal/handlers/auth_handlers.go index c13faa7..941666c 100644 --- a/backend/internal/handlers/auth_handlers.go +++ b/backend/internal/handlers/auth_handlers.go @@ -147,8 +147,45 @@ func (h *AuthHandlers) CallbackGithub(c *gin.Context) { h.logger.Info("Authentication successful for user: " + ghUser.GithubLogin) + c.SetCookie( + "auth_token", + jwtToken, + 3600*24*30, + "/", + "", + true, + true, + ) + + c.Redirect(302, "https://d3m0k1d.ru") +} + +// GetSession godoc +// @Summary Get user session +// @Description Returns user session data +// @Tags auth +// @Produce json +// @Success 200 {object} map[string]interface{} "Session data" +// @Failure 401 {object} map[string]string "Unauthorized" +// @Router /session [get] +func (h *AuthHandlers) GetSession(c *gin.Context) { + tokenString, err := c.Cookie("auth_token") + if err != nil { + c.JSON(401, gin.H{"error": "unauthorized"}) + return + } + + user, err := auth.ValidateJWT(tokenString) + if err != nil { + c.JSON(401, gin.H{"error": "invalid token"}) + return + } + c.JSON(200, gin.H{ - "token": jwtToken, - "user": ghUser, + "user": gin.H{ + "name": user.GithubLogin, + "email": user.Email, + "avatar": user.AvatarURL, + }, }) } diff --git a/backend/internal/handlers/registry_handlers.go b/backend/internal/handlers/registry_handlers.go index b33ac1b..f15e599 100644 --- a/backend/internal/handlers/registry_handlers.go +++ b/backend/internal/handlers/registry_handlers.go @@ -15,6 +15,7 @@ func Register(router *gin.Engine, db *sql.DB) { v1 := router.Group("api/v1") v1.GET("/callback/github", handler_auth.CallbackGithub) v1.GET("/auth/github", handler_auth.LoginGithub) + v1.GET("/session", auth.JWTMiddleware(), handler_auth.GetSession) posts := v1.Group("posts") {