Files
tm_back/internal/user/middleware.go
T
n.nakhostin 98f581ec97 Enhance cursor rules and add user management functionality
- Updated cursor rules to emphasize the importance of dependency injection and logging practices.
- Introduced a new user management domain, including entities, services, handlers, and validation.
- Implemented user authentication features such as login, registration, and role-based access control.
- Added Redis integration for token management and caching.
- Enhanced API documentation with Swagger for user-related endpoints.
- Updated configuration to support new JWT settings and Redis connection parameters.
2025-08-10 14:09:17 +03:30

193 lines
5.8 KiB
Go

package user
import (
"net/http"
"strings"
"tm/pkg/response"
"github.com/google/uuid"
"github.com/labstack/echo/v4"
)
// AuthMiddleware validates JWT access tokens and extracts user information
func (h *Handler) AuthMiddleware() echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
// Extract token from Authorization header
authHeader := c.Request().Header.Get("Authorization")
if authHeader == "" {
return response.Unauthorized(c, "Authorization header required")
}
// Check if it's a Bearer token
if !strings.HasPrefix(authHeader, "Bearer ") {
return response.Unauthorized(c, "Invalid authorization format. Use 'Bearer <token>'")
}
// Extract the token
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
// Validate the access token
validationResult, err := h.authService.ValidateAccessToken(tokenString)
if err != nil {
h.logger.Error("Token validation error", map[string]interface{}{
"error": err.Error(),
})
return response.Unauthorized(c, "Invalid token")
}
if !validationResult.Valid {
if validationResult.Expired {
return response.Unauthorized(c, "Token expired")
}
return response.Unauthorized(c, validationResult.Error)
}
// Extract user information from token
userID, err := uuid.Parse(validationResult.Claims.UserID)
if err != nil {
h.logger.Error("Failed to parse user ID from token", map[string]interface{}{
"error": err.Error(),
})
return response.Unauthorized(c, "Invalid token format")
}
// Store user information in context for handlers to use
c.Set("user_id", userID)
c.Set("user_email", validationResult.Claims.Email)
c.Set("user_role", validationResult.Claims.Role)
c.Set("company_id", validationResult.Claims.CompanyID)
c.Set("access_token", tokenString)
// Continue to next handler
return next(c)
}
}
}
// AdminMiddleware checks if the authenticated user has admin role
func (h *Handler) AdminMiddleware() echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
// Get user role from context (set by AuthMiddleware)
userRole, ok := c.Get("user_role").(string)
if !ok {
return response.Unauthorized(c, "User role not found in context")
}
// Check if user has admin role
if userRole != string(UserRoleAdmin) {
return response.Forbidden(c, "Admin access required")
}
// Continue to next handler
return next(c)
}
}
}
// RoleMiddleware checks if the authenticated user has the required role
func (h *Handler) RoleMiddleware(requiredRole UserRole) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
// Get user role from context (set by AuthMiddleware)
userRole, ok := c.Get("user_role").(string)
if !ok {
return response.Unauthorized(c, "User role not found in context")
}
// Check if user has the required role
if userRole != string(requiredRole) {
return response.Forbidden(c, "Insufficient permissions")
}
// Continue to next handler
return next(c)
}
}
}
// CompanyAccessMiddleware checks if the authenticated user has access to the specified company
func (h *Handler) CompanyAccessMiddleware() echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
// Get user information from context
userRole, ok := c.Get("user_role").(string)
if !ok {
return response.Unauthorized(c, "User role not found in context")
}
// Admin users have access to all companies
if userRole == string(UserRoleAdmin) {
return next(c)
}
// Get company ID from context
userCompanyID, ok := c.Get("company_id").(string)
if !ok || userCompanyID == "" {
return response.Forbidden(c, "Company access not available")
}
// Get company ID from URL parameter
requestedCompanyID := c.Param("company_id")
if requestedCompanyID == "" {
// If no company ID in URL, allow access to user's own company
return next(c)
}
// Check if user has access to the requested company
if userCompanyID != requestedCompanyID {
return response.Forbidden(c, "Access to this company not allowed")
}
// Continue to next handler
return next(c)
}
}
}
// GetUserIDFromContext extracts user ID from Echo context
func GetUserIDFromContext(c echo.Context) (uuid.UUID, error) {
userID, ok := c.Get("user_id").(uuid.UUID)
if !ok {
return uuid.Nil, echo.NewHTTPError(http.StatusUnauthorized, "User ID not found in context")
}
return userID, nil
}
// GetUserEmailFromContext extracts user email from Echo context
func GetUserEmailFromContext(c echo.Context) (string, error) {
userEmail, ok := c.Get("user_email").(string)
if !ok {
return "", echo.NewHTTPError(http.StatusUnauthorized, "User email not found in context")
}
return userEmail, nil
}
// GetUserRoleFromContext extracts user role from Echo context
func GetUserRoleFromContext(c echo.Context) (string, error) {
userRole, ok := c.Get("user_role").(string)
if !ok {
return "", echo.NewHTTPError(http.StatusUnauthorized, "User role not found in context")
}
return userRole, nil
}
// GetCompanyIDFromContext extracts company ID from Echo context
func GetCompanyIDFromContext(c echo.Context) (string, error) {
companyID, ok := c.Get("company_id").(string)
if !ok {
return "", echo.NewHTTPError(http.StatusUnauthorized, "Company ID not found in context")
}
return companyID, nil
}
// GetAccessTokenFromContext extracts access token from Echo context
func GetAccessTokenFromContext(c echo.Context) (string, error) {
accessToken, ok := c.Get("access_token").(string)
if !ok {
return "", echo.NewHTTPError(http.StatusUnauthorized, "Access token not found in context")
}
return accessToken, nil
}