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.POST("/tournaments/:id/join", tournament.JoinTournament)
|
||||||
api.PUT("/tournaments/:id", tournament.UpdateTournament)
|
api.PUT("/tournaments/:id", tournament.UpdateTournament)
|
||||||
|
|
||||||
api.GET("/players", func(c *gin.Context) {
|
// api.GET("/players", func(c *gin.Context) {
|
||||||
player.GetPlayers(c, db.GetDB())
|
// 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) {
|
api.GET("/players/:id", func(c *gin.Context) {
|
||||||
player.GetPlayer(c, db.GetDB(), c.Param("id"))
|
player.GetPlayer(c, db.GetDB(), c.Param("id"))
|
||||||
})
|
})
|
||||||
@@ -72,7 +74,7 @@ func main() {
|
|||||||
// c.JSON(http.StatusOK, gin.H{"message": "Player deleted successfully"})
|
// c.JSON(http.StatusOK, gin.H{"message": "Player deleted successfully"})
|
||||||
})
|
})
|
||||||
api.GET("/teams", func(c *gin.Context) {
|
api.GET("/teams", func(c *gin.Context) {
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
port := os.Getenv("PORT")
|
port := os.Getenv("PORT")
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ func LoginHandler(c *gin.Context, db *sql.DB) {
|
|||||||
// Systemnutzer
|
// Systemnutzer
|
||||||
var token string
|
var token string
|
||||||
var err error
|
var err error
|
||||||
if req.Email == "test@localhost.de" {
|
if req.Email == "test@localhost.de" { //nolint:goconst
|
||||||
token, err = CreateJWT("system-user-id", req.Email, "admin", 60*time.Minute)
|
token, err = CreateJWT("system-user-id", req.Email, []string{"admin"}, 60*time.Minute)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
hash, err := common.HashPassword(req.Password)
|
hash, err := common.HashPassword(req.Password)
|
||||||
@@ -55,7 +55,7 @@ func LoginHandler(c *gin.Context, db *sql.DB) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Create JWT token
|
// 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 {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Token creation error"})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Token creation error"})
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package auth
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v4"
|
"github.com/golang-jwt/jwt/v4"
|
||||||
@@ -10,38 +11,39 @@ import (
|
|||||||
var jwtSecret = []byte("supersecret")
|
var jwtSecret = []byte("supersecret")
|
||||||
|
|
||||||
type Claims struct {
|
type Claims struct {
|
||||||
UserID string
|
UserID string `json:"userId"`
|
||||||
Email string
|
Email string `json:"email"`
|
||||||
Role string
|
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{
|
claims := jwt.MapClaims{
|
||||||
"userId": userID,
|
"userId": userID,
|
||||||
"email": email,
|
"email": email,
|
||||||
"role": role,
|
"role": role,
|
||||||
"exp": time.Now().Add(duration).Unix(),
|
"exp": time.Now().Add(duration).Unix(),
|
||||||
}
|
}
|
||||||
|
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
return token.SignedString(jwtSecret)
|
return token.SignedString(jwtSecret)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseJWT(tokenStr string) (*Claims, error) {
|
func ParseJWT(tokenString string) (*Claims, error) {
|
||||||
token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, 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
|
return jwtSecret, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// C. Validierung
|
||||||
if err != nil || !token.Valid {
|
if err != nil || !token.Valid {
|
||||||
|
|
||||||
return nil, errors.New("invalid token")
|
return nil, errors.New("invalid token")
|
||||||
}
|
}
|
||||||
claims, ok := token.Claims.(jwt.MapClaims)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("invalid claims")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Claims{
|
return claims, nil
|
||||||
UserID: claims["userId"].(string),
|
|
||||||
Email: claims["email"].(string),
|
|
||||||
Role: claims["role"].(string),
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,15 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"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 {
|
func AuthMiddleware() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
authHeader := c.GetHeader("Authorization")
|
authHeader := c.GetHeader("Authorization")
|
||||||
@@ -28,3 +37,43 @@ func AuthMiddleware() gin.HandlerFunc {
|
|||||||
c.Next()
|
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) {
|
func GetPlayers(c *gin.Context, db *sql.DB) {
|
||||||
|
// log.Println(c.)
|
||||||
log.Println(c.GetString("userId"), c.GetString("email"), c.GetString("role"))
|
log.Println(c.GetString("userId"), c.GetString("email"), c.GetString("role"))
|
||||||
// Simulate fetching players from a database
|
// Simulate fetching players from a database
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { jwtDecode } from 'jwt-decode';
|
|||||||
export interface TokenPayload {
|
export interface TokenPayload {
|
||||||
userId: string;
|
userId: string;
|
||||||
email: string;
|
email: string;
|
||||||
role: string;
|
role: string[];
|
||||||
exp: number;
|
exp: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { getUserFromToken } from '../components/utils/jwt';
|
|||||||
interface AuthContextType {
|
interface AuthContextType {
|
||||||
token: string | null;
|
token: string | null;
|
||||||
userId: string | null;
|
userId: string | null;
|
||||||
login: (token: string, userId: string, role: string) => void;
|
login: (token: string, userId: string, role: string[]) => void;
|
||||||
logout: () => void;
|
logout: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ const AuthContext = createContext<AuthContextType | undefined>(undefined);
|
|||||||
export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||||
const [token, setToken] = useState<string | null>(null);
|
const [token, setToken] = useState<string | null>(null);
|
||||||
const [userId, setUserId] = 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(() => {
|
useEffect(() => {
|
||||||
const storedToken = localStorage.getItem('token');
|
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);
|
setToken(token);
|
||||||
setUserId(userId);
|
setUserId(userId);
|
||||||
setRole(role);
|
setRole(role);
|
||||||
localStorage.setItem('token', token);
|
localStorage.setItem('token', token);
|
||||||
localStorage.setItem('userId', userId);
|
localStorage.setItem('userId', userId);
|
||||||
localStorage.setItem('role', role);
|
localStorage.setItem('role', JSON.stringify(role)); // Store array as string
|
||||||
};
|
};
|
||||||
|
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const TeamManagement = () => {
|
|||||||
|
|
||||||
const token = localStorage.getItem('token');
|
const token = localStorage.getItem('token');
|
||||||
const user = token ? getUserFromToken(token) : null;
|
const user = token ? getUserFromToken(token) : null;
|
||||||
const isAdmin = user?.role === 'admin';
|
const isAdmin = user?.role?.includes('admin');
|
||||||
|
|
||||||
const fetchTeams = async () => {
|
const fetchTeams = async () => {
|
||||||
const res = await fetch('/api/teams', {
|
const res = await fetch('/api/teams', {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const ViewEditPlayer = () => {
|
|||||||
const { id } = useParams<{ id: string }>();
|
const { id } = useParams<{ id: string }>();
|
||||||
const token = localStorage.getItem('token');
|
const token = localStorage.getItem('token');
|
||||||
const currentUser = token ? getUserFromToken(token) : null;
|
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 [player, setPlayer] = useState<User | null>(null);
|
||||||
const [name, setName] = useState('');
|
const [name, setName] = useState('');
|
||||||
|
|||||||
Reference in New Issue
Block a user