ADD: added new auth middleware and changed the roles value ind the jwt token to a array
This commit is contained in:
@@ -54,9 +54,11 @@ func main() {
|
||||
api.POST("/tournaments/:id/join", tournament.JoinTournament)
|
||||
api.PUT("/tournaments/:id", tournament.UpdateTournament)
|
||||
|
||||
api.GET("/players", func(c *gin.Context) {
|
||||
player.GetPlayers(c, db.GetDB())
|
||||
})
|
||||
// api.GET("/players", func(c *gin.Context) {
|
||||
// player.GetPlayers(c, db.GetDB())
|
||||
// })
|
||||
api.GET("/players", auth.AuthorizeJWT("admin"), func(c *gin.Context) { player.GetPlayers(c, db.GetDB()) })
|
||||
|
||||
api.GET("/players/:id", func(c *gin.Context) {
|
||||
player.GetPlayer(c, db.GetDB(), c.Param("id"))
|
||||
})
|
||||
@@ -72,7 +74,7 @@ func main() {
|
||||
// c.JSON(http.StatusOK, gin.H{"message": "Player deleted successfully"})
|
||||
})
|
||||
api.GET("/teams", func(c *gin.Context) {
|
||||
|
||||
|
||||
})
|
||||
|
||||
port := os.Getenv("PORT")
|
||||
|
||||
@@ -35,8 +35,8 @@ func LoginHandler(c *gin.Context, db *sql.DB) {
|
||||
// Systemnutzer
|
||||
var token string
|
||||
var err error
|
||||
if req.Email == "test@localhost.de" {
|
||||
token, err = CreateJWT("system-user-id", req.Email, "admin", 60*time.Minute)
|
||||
if req.Email == "test@localhost.de" { //nolint:goconst
|
||||
token, err = CreateJWT("system-user-id", req.Email, []string{"admin"}, 60*time.Minute)
|
||||
} else {
|
||||
|
||||
hash, err := common.HashPassword(req.Password)
|
||||
@@ -55,7 +55,7 @@ func LoginHandler(c *gin.Context, db *sql.DB) {
|
||||
return
|
||||
}
|
||||
// Create JWT token
|
||||
token, err = CreateJWT(loggedInPlayer.UUID, req.Email, "player", 60*time.Minute)
|
||||
token, err = CreateJWT(loggedInPlayer.UUID, req.Email, []string{"player"}, 60*time.Minute)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Token creation error"})
|
||||
return
|
||||
|
||||
@@ -2,6 +2,7 @@ package auth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
@@ -10,38 +11,39 @@ import (
|
||||
var jwtSecret = []byte("supersecret")
|
||||
|
||||
type Claims struct {
|
||||
UserID string
|
||||
Email string
|
||||
Role string
|
||||
UserID string `json:"userId"`
|
||||
Email string `json:"email"`
|
||||
Role []string `json:"role"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
func CreateJWT(userID, email, role string, duration time.Duration) (string, error) {
|
||||
func CreateJWT(userID string, email string, role []string, duration time.Duration) (string, error) {
|
||||
claims := jwt.MapClaims{
|
||||
"userId": userID,
|
||||
"email": email,
|
||||
"role": role,
|
||||
"exp": time.Now().Add(duration).Unix(),
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
return token.SignedString(jwtSecret)
|
||||
}
|
||||
|
||||
func ParseJWT(tokenStr string) (*Claims, error) {
|
||||
token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
|
||||
func ParseJWT(tokenString string) (*Claims, error) {
|
||||
|
||||
claims := &Claims{}
|
||||
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
|
||||
// Algorithmus Check (Sicherheit)
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("unerwartete Signing-Methode: %v", token.Header["alg"])
|
||||
}
|
||||
return jwtSecret, nil
|
||||
})
|
||||
|
||||
// C. Validierung
|
||||
if err != nil || !token.Valid {
|
||||
|
||||
return nil, errors.New("invalid token")
|
||||
}
|
||||
claims, ok := token.Claims.(jwt.MapClaims)
|
||||
if !ok {
|
||||
return nil, errors.New("invalid claims")
|
||||
}
|
||||
|
||||
return &Claims{
|
||||
UserID: claims["userId"].(string),
|
||||
Email: claims["email"].(string),
|
||||
Role: claims["role"].(string),
|
||||
}, nil
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,15 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func contains(slice []string, item string) bool {
|
||||
for _, s := range slice {
|
||||
if s == item {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func AuthMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
authHeader := c.GetHeader("Authorization")
|
||||
@@ -28,3 +37,43 @@ func AuthMiddleware() gin.HandlerFunc {
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func AuthorizeJWT(requiredRole string) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
//A. Token aus Header holen
|
||||
authHeader := c.GetHeader("Authorization")
|
||||
if authHeader == "" {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Authorization Header fehlt"})
|
||||
return
|
||||
}
|
||||
|
||||
// "Bearer " entfernen
|
||||
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
|
||||
if tokenString == authHeader {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Token Format muss 'Bearer <token>' sein"})
|
||||
return
|
||||
}
|
||||
|
||||
claims, err := ParseJWT(tokenString)
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Token ungültig oder abgelaufen"})
|
||||
}
|
||||
// --- NEUE LOGIK ---
|
||||
// Wir prüfen: Hat der User die geforderte Rolle ODER ist er "admin"?
|
||||
// (Angenommen "admin" darf alles. Falls nicht, entferne den "admin"-Check)
|
||||
userHasRequiredRole := contains(claims.Role, requiredRole)
|
||||
userIsAdmin := contains(claims.Role, "admin")
|
||||
|
||||
if !userHasRequiredRole && !userIsAdmin {
|
||||
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "Keine Berechtigung"})
|
||||
return
|
||||
}
|
||||
|
||||
// User und Rollen im Context speichern (als Interface{}, daher später casten)
|
||||
c.Set("userId", claims.UserID)
|
||||
c.Set("email", claims.Email)
|
||||
c.Set("role", claims.Role)
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func GetPlayers(c *gin.Context, db *sql.DB) {
|
||||
// log.Println(c.)
|
||||
log.Println(c.GetString("userId"), c.GetString("email"), c.GetString("role"))
|
||||
// Simulate fetching players from a database
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { jwtDecode } from 'jwt-decode';
|
||||
export interface TokenPayload {
|
||||
userId: string;
|
||||
email: string;
|
||||
role: string;
|
||||
role: string[];
|
||||
exp: number;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { getUserFromToken } from '../components/utils/jwt';
|
||||
interface AuthContextType {
|
||||
token: string | null;
|
||||
userId: string | null;
|
||||
login: (token: string, userId: string, role: string) => void;
|
||||
login: (token: string, userId: string, role: string[]) => void;
|
||||
logout: () => void;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ const AuthContext = createContext<AuthContextType | undefined>(undefined);
|
||||
export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const [token, setToken] = useState<string | null>(null);
|
||||
const [userId, setUserId] = useState<string | null>(null);
|
||||
const [role, setRole] = useState<string | null>(null);
|
||||
const [role, setRole] = useState<string[] | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const storedToken = localStorage.getItem('token');
|
||||
@@ -40,13 +40,13 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
||||
|
||||
}, []);
|
||||
|
||||
const login = (token: string, userId: string, role: string) => {
|
||||
const login = (token: string, userId: string, role: string[]) => {
|
||||
setToken(token);
|
||||
setUserId(userId);
|
||||
setRole(role);
|
||||
localStorage.setItem('token', token);
|
||||
localStorage.setItem('userId', userId);
|
||||
localStorage.setItem('role', role);
|
||||
localStorage.setItem('role', JSON.stringify(role)); // Store array as string
|
||||
};
|
||||
|
||||
const logout = () => {
|
||||
|
||||
@@ -19,7 +19,7 @@ const TeamManagement = () => {
|
||||
|
||||
const token = localStorage.getItem('token');
|
||||
const user = token ? getUserFromToken(token) : null;
|
||||
const isAdmin = user?.role === 'admin';
|
||||
const isAdmin = user?.role?.includes('admin');
|
||||
|
||||
const fetchTeams = async () => {
|
||||
const res = await fetch('/api/teams', {
|
||||
|
||||
@@ -9,7 +9,7 @@ const ViewEditPlayer = () => {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const token = localStorage.getItem('token');
|
||||
const currentUser = token ? getUserFromToken(token) : null;
|
||||
const isAdmin = currentUser?.role === 'admin';
|
||||
const isAdmin = currentUser?.role?.includes('admin');
|
||||
|
||||
const [player, setPlayer] = useState<User | null>(null);
|
||||
const [name, setName] = useState('');
|
||||
|
||||
Reference in New Issue
Block a user