heruvym/middleware/http_middleware.go
2024-11-26 02:11:24 +03:00

260 lines
7.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package middleware
import (
"context"
"fmt"
"heruvym/jwt_adapter"
"net/http"
"strings"
"time"
errors2 "github.com/pkg/errors"
"github.com/rs/xid"
"gitea.pena/PenaSide/hlog"
)
// My MiddleWare with gorilla/mux
type Middleware struct {
logger hlog.Logger
// mongo dal.LayerMongoDb
allowedOrigins string
allowedRoles map[string]string // key - path, value - roles
}
const sessionKey = "Sess"
const HostKey = "host"
func NewMiddleware(
logger hlog.Logger,
//mongo dal.LayerMongoDb,
allowedOrigins string,
allowedRoles map[string]string,
) *Middleware {
return &Middleware{
logger: logger,
allowedOrigins: allowedOrigins,
allowedRoles: allowedRoles,
}
}
func (mw *Middleware) MiddlewareLogger(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
mw.logger.Emit(DebugHttpRequest{Url: r.URL.String()})
next.ServeHTTP(w, r)
})
}
func (mw *Middleware) MiddlewareOriginAccess(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if len(r.Header["Origin"]) > 0 {
if mw.allowedOrigins != "*" && !strings.Contains(mw.allowedOrigins, r.Header["Origin"][0]) {
mw.logger.Emit(ErrorOriginAccess{Origin: r.Header["Origin"][0], Url: r.URL.String()})
return
}
}
next.ServeHTTP(w, r)
})
}
func recFn(rec interface{}) (int, string) {
var (
code int
message string
)
if err, ok := rec.(error); ok {
code = http.StatusInternalServerError
message = err.Error()
} else {
code = http.StatusInternalServerError
message = fmt.Sprintf("%v", rec)
}
return code, message
}
func (mw *Middleware) MiddlewareRecovery(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if rec := recover(); rec != nil {
code, message := recFn(rec)
w.WriteHeader(code)
if _, err := fmt.Fprint(w, message); err != nil {
mw.logger.Emit(ErrorWritingPanicResponse{Err: err})
}
mw.logger.Emit(ErrorPanicInHttpHandler{
Code: code,
Message: message,
Recovered: rec,
})
}
}()
next.ServeHTTP(w, r)
})
}
func (mw *Middleware) MiddlewareJwt(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var (
token, role string
adapter *jwt_adapter.JwtAdapter
)
switch r.Header["Referer"][0] {
case "sadmin.pena":
role = "admin"
case "admin.pena":
role = "admin"
default:
role = "user"
}
ctx := context.WithValue(r.Context(), jwt_adapter.RoleKey, role)
tokenCookie, err := r.Cookie(jwt_adapter.DefaultHeaderKey)
fmt.Println("MW1", err)
if err != nil {
// Escape GET requests
if r.Method == http.MethodGet {
next.ServeHTTP(w, r.WithContext(ctx))
return
}
fmt.Println("MW2", jwt_adapter.DefaultHeaderKey, r.Header[jwt_adapter.DefaultHeaderKey])
if len(r.Header[jwt_adapter.DefaultHeaderKey]) <= 0 || !func(hdrs []string) bool {
if len(hdrs) == 0 {return false}
fmt.Println("SS", hdrs[0])
if hdrs[0] == "Bearer" || hdrs[0] == "Bearer " {
return false
}
return true
}(r.Header[jwt_adapter.DefaultHeaderKey]) {
fmt.Println("MW3", r.Header[sessionKey], sessionKey, r.Header)
if len(r.Header[sessionKey]) == 0 {
if sessCookie, err := r.Cookie(sessionKey); err != nil {
id := xid.New().String()
adapter = &jwt_adapter.JwtAdapter{Id: id}
http.SetCookie(w, &http.Cookie{
Name: sessionKey,
Value: id,
Expires: time.Now().Add(time.Hour * 24 * 30),
SameSite: http.SameSiteNoneMode,
Secure: true,
})
fmt.Println("SSS", sessCookie, err)
} else {
fmt.Println("SSS1", sessCookie.Value, err)
adapter = &jwt_adapter.JwtAdapter{Id: sessCookie.Value}
}
} else {
adapter = &jwt_adapter.JwtAdapter{Id: r.Header[sessionKey][0]}
}
} else {
token = r.Header[jwt_adapter.DefaultHeaderKey][0]
token = strings.Replace(token, "Bearer ", "", -1)
}
} else {
token = tokenCookie.Value
}
if adapter == nil {
adapter, err = jwt_adapter.Decode(token)
if err != nil {
mw.logger.Emit(ErrorJwtAccess{Err: err})
w.WriteHeader(http.StatusUnauthorized)
return
}
}
err = setJwtHeader(adapter, w, mw.logger)
if err != nil {
mw.logger.Emit(ErrorJwtAccess{Err: err})
w.WriteHeader(http.StatusUnauthorized)
return
}
ctx = context.WithValue(ctx, jwt_adapter.DefaultHeaderKey, adapter)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
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))
})
}
*/
func (mw *Middleware) ExtractHostMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
host := r.Header["Referer"][0]
ctx := context.WithValue(r.Context(), HostKey, host)
next.ServeHTTP(w, r.WithContext(ctx))
})
}