first commit

This commit is contained in:
Beyhan Oğur
2026-04-26 21:46:42 +03:00
commit 2a5b661443
202 changed files with 49770 additions and 0 deletions

127
app/services/jwt_service.go Normal file
View File

@@ -0,0 +1,127 @@
package services
import (
"errors"
"fmt"
configs "goGin/config"
"time"
"github.com/golang-jwt/jwt/v5"
)
// TokenTypeAccess sabiti, auth middleware'in beklediği token türünü temsil eder.
const TokenTypeAccess = "access"
// JWTClaim, authorization middleware'inin beklediği claim yapısını temsil eder.
// İleride ihtiyaç oldukça alanlar genişletilebilir.
type JWTClaim struct {
TokenType string
IsAdmin bool
UserID any
}
// JWTService, JWT ile ilgili operasyonları kapsayan servis.
type JWTService struct {
secret []byte
}
// NewJWTService yeni bir JWTService örneği döner.
// Secret, config içindeki JWT_SECRET üzerinden okunur.
func NewJWTService() *JWTService {
secret := ""
if configs.AppConfig != nil {
secret = configs.AppConfig.JWTSecret
}
return &JWTService{
secret: []byte(secret),
}
}
// ValidateToken verilen JWT'yi doğrular ve claim'leri döner.
// HMAC (HS256 vb.) ile imzalanmış token'lar beklenir.
func (s *JWTService) ValidateToken(tokenString string) (*JWTClaim, error) {
if len(s.secret) == 0 {
return nil, errors.New("jwt secret is not configured")
}
token, err := jwt.Parse(tokenString, func(t *jwt.Token) (interface{}, error) {
// Sadece HMAC algoritmalarına izin veriyoruz.
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
}
return s.secret, nil
})
if err != nil {
return nil, err
}
if !token.Valid {
return nil, errors.New("invalid token")
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
return nil, errors.New("invalid token claims")
}
// Token tipi (access / refresh vs.)
var tokenType string
if v, ok := claims["token_type"].(string); ok {
tokenType = v
} else if v, ok := claims["tokenType"].(string); ok {
tokenType = v
}
// Yönetici flag'i
var isAdmin bool
if v, ok := claims["is_admin"]; ok {
switch vv := v.(type) {
case bool:
isAdmin = vv
case float64:
isAdmin = vv != 0
}
} else if v, ok := claims["isAdmin"]; ok {
if vv, ok2 := v.(bool); ok2 {
isAdmin = vv
}
}
// Kullanıcı ID'si (sub claim'i üzerinden)
var userID any
if v, ok := claims["sub"]; ok {
userID = v
} else if v, ok := claims["user_id"]; ok {
userID = v
}
return &JWTClaim{
TokenType: tokenType,
IsAdmin: isAdmin,
UserID: userID,
}, nil
}
// GenerateToken creates a short-lived access token
func (s *JWTService) GenerateToken(userID uint, isAdmin bool) (string, error) {
claims := jwt.MapClaims{
"sub": userID,
"is_admin": isAdmin,
"token_type": TokenTypeAccess,
"exp": jwt.NewNumericDate(time.Now().Add(time.Duration(configs.AppConfig.AccessTokenExpireMinutes) * time.Minute)),
"iat": jwt.NewNumericDate(time.Now()),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(s.secret)
}
// GenerateRefreshToken creates a long-lived refresh token
func (s *JWTService) GenerateRefreshToken(userID uint) (string, error) {
claims := jwt.MapClaims{
"sub": userID,
"token_type": "refresh",
"exp": jwt.NewNumericDate(time.Now().Add(time.Duration(configs.AppConfig.RefreshTokenExpireDays) * 24 * time.Hour)),
"iat": jwt.NewNumericDate(time.Now()),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(s.secret)
}