heruvym/middleware/http_middleware.go

241 lines
6.0 KiB
Go
Raw Normal View History

2021-05-15 14:03:10 +00:00
package middleware
2021-04-11 09:48:15 +00:00
import (
"fmt"
2024-09-25 10:18:19 +00:00
"github.com/gofiber/fiber/v2"
2021-09-05 15:24:13 +00:00
"heruvym/jwt_adapter"
2021-04-11 09:48:15 +00:00
"strings"
"time"
2023-03-01 17:38:03 +00:00
"github.com/rs/xid"
2023-03-01 17:38:03 +00:00
"github.com/themakers/hlog"
2021-04-11 09:48:15 +00:00
)
2021-05-15 14:03:10 +00:00
// My MiddleWare with gorilla/mux
type Middleware struct {
2023-03-01 17:38:03 +00:00
logger hlog.Logger
// mongo dal.LayerMongoDb
2021-05-15 14:03:10 +00:00
allowedOrigins string
allowedRoles map[string]string // key - path, value - roles
2021-04-11 09:48:15 +00:00
}
2023-04-12 21:37:28 +00:00
const sessionKey = "Sess"
const HostKey = "host"
2021-05-15 14:03:10 +00:00
func NewMiddleware(
logger hlog.Logger,
2023-03-01 17:38:03 +00:00
//mongo dal.LayerMongoDb,
2021-05-15 14:03:10 +00:00
allowedOrigins string,
allowedRoles map[string]string,
) *Middleware {
return &Middleware{
2023-04-12 20:44:12 +00:00
logger: logger,
2021-05-15 14:03:10 +00:00
allowedOrigins: allowedOrigins,
allowedRoles: allowedRoles,
}
}
2021-04-11 09:48:15 +00:00
2024-09-25 10:18:19 +00:00
func (mw *Middleware) MiddlewareLogger(ctx *fiber.Ctx) error {
mw.logger.Emit(DebugHttpRequest{
Url: ctx.OriginalURL(),
2021-05-15 14:03:10 +00:00
})
2024-09-25 10:18:19 +00:00
return ctx.Next()
2021-05-15 14:03:10 +00:00
}
2021-04-11 09:48:15 +00:00
2024-09-25 10:18:19 +00:00
func (mw *Middleware) MiddlewareOriginAccess(ctx *fiber.Ctx) error {
origin := ctx.Get("Origin")
if origin == "" {
if mw.allowedOrigins != "*" && !strings.Contains(mw.allowedOrigins, origin) {
mw.logger.Emit(ErrorOriginAccess{
Origin: origin,
Url: ctx.OriginalURL(),
})
return ctx.SendStatus(fiber.StatusForbidden)
2021-05-15 14:03:10 +00:00
}
2024-09-25 10:18:19 +00:00
}
return ctx.Next()
2021-05-15 14:03:10 +00:00
}
2021-05-01 10:05:45 +00:00
2021-05-15 14:03:10 +00:00
func recFn(rec interface{}) (int, string) {
var (
code int
message string
)
if err, ok := rec.(error); ok {
2024-09-25 10:18:19 +00:00
code = fiber.StatusInternalServerError
2023-03-01 17:38:03 +00:00
message = err.Error()
2021-05-15 14:03:10 +00:00
} else {
2024-09-25 10:18:19 +00:00
code = fiber.StatusInternalServerError
2021-05-15 14:03:10 +00:00
message = fmt.Sprintf("%v", rec)
}
2021-04-11 09:48:15 +00:00
2021-05-15 14:03:10 +00:00
return code, message
}
2021-04-11 09:48:15 +00:00
2024-09-25 10:18:19 +00:00
func (mw *Middleware) MiddlewareRecovery(ctx *fiber.Ctx) error {
defer func() {
if rec := recover(); rec != nil {
code, message := recFn(rec)
ctx.Status(code)
if _, err := ctx.WriteString(message); err != nil {
mw.logger.Emit(ErrorWritingPanicResponse{Err: err})
2021-04-11 09:48:15 +00:00
}
2024-09-25 10:18:19 +00:00
mw.logger.Emit(ErrorPanicInHttpHandler{
Code: code,
Message: message,
Recovered: rec,
})
}
}()
return ctx.Next()
2021-05-15 14:03:10 +00:00
}
2021-04-11 09:48:15 +00:00
2024-09-25 10:18:19 +00:00
func (mw *Middleware) MiddlewareJwt(ctx *fiber.Ctx) error {
var (
token, role string
adapter *jwt_adapter.JwtAdapter
err error
)
2021-04-11 09:48:15 +00:00
2024-09-25 10:18:19 +00:00
switch ctx.Get("Referer") {
case "sadmin.pena":
role = "admin"
case "admin.pena":
role = "admin"
default:
role = "user"
}
2024-09-25 10:18:19 +00:00
ctx.Locals(jwt_adapter.RoleKey, role)
tokenCookie := ctx.Cookies(jwt_adapter.DefaultHeaderKey)
if tokenCookie == "" {
if ctx.Method() == "GET" {
return ctx.Next()
2023-03-01 17:38:03 +00:00
}
2024-09-25 10:18:19 +00:00
headerToken := ctx.Get(jwt_adapter.DefaultHeaderKey)
if headerToken == "" || !strings.HasPrefix(headerToken, "Bearer") {
if ctx.Get(sessionKey) == "" {
sessCookie := ctx.Cookies(sessionKey)
if sessCookie == "" {
id := xid.New().String()
adapter = &jwt_adapter.JwtAdapter{Id: id}
ctx.Cookie(&fiber.Cookie{
Name: sessionKey,
Value: id,
Expires: time.Now().Add(time.Hour * 24 * 30),
SameSite: fiber.CookieSameSiteNoneMode,
Secure: true,
})
} else {
2024-09-25 10:18:19 +00:00
adapter = &jwt_adapter.JwtAdapter{Id: sessCookie}
}
} else {
2024-09-25 10:18:19 +00:00
adapter = &jwt_adapter.JwtAdapter{Id: ctx.Get(sessionKey)}
2021-09-05 15:24:13 +00:00
}
} else {
2024-09-25 10:18:19 +00:00
token = strings.Replace(headerToken, "Bearer ", "", -1)
2021-04-11 09:48:15 +00:00
}
2024-09-25 10:18:19 +00:00
} else {
token = tokenCookie
}
2021-04-11 09:48:15 +00:00
2024-09-25 10:18:19 +00:00
if adapter == nil {
adapter, err = jwt_adapter.Decode(token)
2021-05-15 14:03:10 +00:00
if err != nil {
mw.logger.Emit(ErrorJwtAccess{Err: err})
2024-09-25 10:18:19 +00:00
return ctx.Status(fiber.StatusUnauthorized).SendString("Unauthorized")
2021-05-15 14:03:10 +00:00
}
2021-04-11 09:48:15 +00:00
}
2024-09-25 10:18:19 +00:00
err = setJwtHeader(adapter, ctx.Response(), mw.logger)
if err != nil {
mw.logger.Emit(ErrorJwtAccess{Err: err})
return ctx.Status(fiber.StatusUnauthorized).SendString("Unauthorized")
}
2021-04-11 09:48:15 +00:00
2024-09-25 10:18:19 +00:00
ctx.Locals(jwt_adapter.DefaultHeaderKey, adapter)
return ctx.Next()
2021-05-15 14:03:10 +00:00
}
2021-04-11 09:48:15 +00:00
2024-09-25 10:18:19 +00:00
func (mw *Middleware) ExtractHostMiddleware(ctx *fiber.Ctx) error {
host := ctx.Get("Referer")
if host != "" {
ctx.Locals(HostKey, host)
}
return ctx.Next()
2021-04-11 09:48:15 +00:00
}
2024-09-25 10:18:19 +00:00
// todo useless?
//func getJwtUserId(r *http.Request) (string, error) {
// if jwtAdapter, ok := r.Context().Value(jwt_adapter.DefaultHeaderKey).(*jwt_adapter.JwtAdapter); ok {
// return jwtAdapter.Id, nil
// }
//
// return "", errors2.New("no token in context")
//}
//
//func (mw *Middleware) MiddlewareRoleAccess(next http.Handler) http.Handler {
// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// // Если доступ по роли задан
// if allowedRoles, ok := mw.allowedRoles[r.URL.Path]; ok {
//
// // Если роли не указаны
// if allowedRoles == "" {
// next.ServeHTTP(w, r)
// return
// }
// /*
// id, err := getJwtUserId(r)
//
// if err != nil {
// mw.logger.Emit(ErrorRoleAccess{Err: err})
// http.Error(w, "internal server error", http.StatusInternalServerError)
// return
// }*/
// /*
// role, err := mw.mongo.GetProfileRole(r.Context(), id)
//
// if err != nil {
// mw.logger.Emit(ErrorRoleAccess{Err: err})
// http.Error(w, "internal server error", http.StatusInternalServerError)
// return
// }
// */
// // Если у пользователя не задана роль - блокируем доступ
// /* if role == "" {
// err = errors.UserHaveNoRole("User have no role")
// mw.logger.Emit(ErrorRoleAccess{err})
// http.Error(w, err.Error(), http.StatusForbidden)
// return
// }
//
// // Если указан астериск - доступ имеет любая роль
// if !(allowedRoles == "*" || strings.Contains(allowedRoles, role)) {
// err = errors.UserHaveNoRole("User role not allowed")
// mw.logger.Emit(ErrorRoleAccess{err})
// http.Error(w, err.Error(), http.StatusForbidden)
// return
// }*/
// }
//
// next.ServeHTTP(w, r)
// })
//}
//
//// MiddlewareJwtPlug jwt заглушка для отладки кода, удалить в релизе
///*
//func (mw *Middleware) MiddlewareJwtPlug(next http.Handler) http.Handler {
// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// adapter := jwt_adapter.JwtAdapter{ID: "604b79aced1d431b9e911f56"}
// adapter.Init()
// adapter.SetUserID("604b79aced1d431b9e911f56")
// ctx := context.WithValue(r.Context(), "JWT", &adapter)
//
// next.ServeHTTP(w, r.WithContext(ctx))
// })
//}
//*/