ilk
This commit is contained in:
47
svc/auth/claims.go
Normal file
47
svc/auth/claims.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
type Claims struct {
|
||||
// ==================================================
|
||||
// 🔑 IDENTITY
|
||||
// ==================================================
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
RoleID int64 `json:"role_id"`
|
||||
|
||||
RoleCode string `json:"role_code"`
|
||||
DepartmentCodes []string `json:"department_codes"`
|
||||
|
||||
// ==================================================
|
||||
// 🧾 NEBIM (frontend filtre & backend guard için)
|
||||
// ==================================================
|
||||
V3Username string `json:"v3_username"`
|
||||
V3UserGroup string `json:"v3_usergroup"`
|
||||
|
||||
// ==================================================
|
||||
// 🔐 SESSION
|
||||
// ==================================================
|
||||
SessionID string `json:"session_id"`
|
||||
|
||||
// ==================================================
|
||||
// ⚠️ SECURITY
|
||||
// ==================================================
|
||||
ForcePasswordChange bool `json:"force_password_change"`
|
||||
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
func (c *Claims) IsAdmin() bool {
|
||||
if c == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
role := strings.ToLower(strings.TrimSpace(c.RoleCode))
|
||||
|
||||
return role == "admin"
|
||||
}
|
||||
36
svc/auth/claims_mapper.go
Normal file
36
svc/auth/claims_mapper.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"bssapp-backend/models"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
func BuildClaimsFromUser(u *models.MkUser, ttl time.Duration) Claims {
|
||||
now := time.Now()
|
||||
|
||||
return Claims{
|
||||
// 🔴 mk_dfusr.id
|
||||
ID: u.ID,
|
||||
|
||||
Username: u.Username,
|
||||
RoleCode: u.RoleCode,
|
||||
RoleID: u.RoleID,
|
||||
// ✅ BURASI
|
||||
DepartmentCodes: u.DepartmentCodes,
|
||||
|
||||
SessionID: u.SessionID,
|
||||
|
||||
ForcePasswordChange: u.ForcePasswordChange,
|
||||
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
Issuer: "bssapp",
|
||||
Subject: u.Username,
|
||||
IssuedAt: jwt.NewNumericDate(now),
|
||||
NotBefore: jwt.NewNumericDate(now),
|
||||
ExpiresAt: jwt.NewNumericDate(now.Add(ttl)),
|
||||
},
|
||||
}
|
||||
}
|
||||
15
svc/auth/context.go
Normal file
15
svc/auth/context.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"bssapp-backend/ctxkeys"
|
||||
"context"
|
||||
)
|
||||
|
||||
func WithClaims(ctx context.Context, claims *Claims) context.Context {
|
||||
return context.WithValue(ctx, ctxkeys.UserContextKey, claims)
|
||||
}
|
||||
|
||||
func GetClaimsFromContext(ctx context.Context) (*Claims, bool) {
|
||||
claims, ok := ctx.Value(ctxkeys.UserContextKey).(*Claims)
|
||||
return claims, ok
|
||||
}
|
||||
53
svc/auth/jwt.go
Normal file
53
svc/auth/jwt.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
// package auth
|
||||
|
||||
func jwtSecret() ([]byte, error) {
|
||||
sec := os.Getenv("JWT_SECRET")
|
||||
if len(sec) < 10 {
|
||||
return nil, errors.New("JWT_SECRET environment boş veya çok kısa")
|
||||
}
|
||||
return []byte(sec), nil
|
||||
}
|
||||
|
||||
// ✅ TEK VE DOĞRU TOKEN ÜRETİCİ
|
||||
func GenerateToken(claims Claims, username string, change bool) (string, error) {
|
||||
secret, err := jwtSecret()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
return token.SignedString(secret)
|
||||
}
|
||||
|
||||
func ValidateToken(tokenStr string) (*Claims, error) {
|
||||
secret, err := jwtSecret()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
token, err := jwt.ParseWithClaims(
|
||||
tokenStr,
|
||||
&Claims{},
|
||||
func(token *jwt.Token) (interface{}, error) {
|
||||
return secret, nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
claims, ok := token.Claims.(*Claims)
|
||||
if !ok || !token.Valid {
|
||||
return nil, errors.New("token geçersiz")
|
||||
}
|
||||
return claims, nil
|
||||
}
|
||||
44
svc/auth/logout.go
Normal file
44
svc/auth/logout.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"bssapp-backend/internal/auditlog"
|
||||
"bssapp-backend/repository"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func LogoutAllHandler(db *sql.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
claims, ok := GetClaimsFromContext(r.Context())
|
||||
if !ok || claims == nil {
|
||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
userID := claims.ID
|
||||
|
||||
_ = repository.NewRefreshTokenRepository(db).
|
||||
RevokeAllForUser(userID)
|
||||
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "mk_refresh",
|
||||
Value: "",
|
||||
Path: "/",
|
||||
Expires: time.Unix(0, 0),
|
||||
HttpOnly: true,
|
||||
})
|
||||
|
||||
auditlog.Write(auditlog.ActivityLog{
|
||||
UserID: auditlog.IntUserIDToUUID(int(userID)),
|
||||
ActionType: "logout_all",
|
||||
ActionCategory: "auth",
|
||||
Description: "user logged out from all devices",
|
||||
IsSuccess: true,
|
||||
})
|
||||
|
||||
_ = json.NewEncoder(w).Encode(map[string]bool{"success": true})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user