Files

79 lines
1.8 KiB
Go
Raw Permalink Normal View History

2026-06-15 11:43:11 +02:00
package auth
import (
"context"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"net/http"
)
type User struct {
Email string `json:"email"`
Roles []string `json:"roles"`
}
func (u *User) HasRole(role ...string) bool {
for _, r := range role {
for _, o := range u.Roles {
if r == o {
return true
}
}
}
return false
}
type ContextKey string
const (
UserKey = ContextKey("user")
)
func UserMiddleware(signingKey []byte) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user := &User{}
header := r.Header.Get("user")
if len(header) == 0 {
fmt.Println("User not found in request headers, check api-gateway")
next.ServeHTTP(w, r)
return
}
if len(signingKey) > 0 {
signature := r.Header.Get("user-signature")
if signature == "" {
http.Error(w, "missing user-signature header", http.StatusUnauthorized)
return
}
mac := hmac.New(sha256.New, signingKey)
mac.Write([]byte(header))
expected := hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(signature), []byte(expected)) {
http.Error(w, "invalid user-signature", http.StatusUnauthorized)
return
}
}
if err := json.Unmarshal([]byte(header), &user); err != nil {
fmt.Printf("User in header (%s) not parseable, check api-gateway", header)
next.ServeHTTP(w, r)
} else {
ctx := context.WithValue(r.Context(), UserKey, user)
next.ServeHTTP(w, r.WithContext(ctx))
}
})
}
}
func FromContext(ctx context.Context) *User {
if user := ctx.Value(UserKey); user != nil {
if u, ok := user.(*User); ok {
return u
}
fmt.Println("User in context is not the correct type")
}
return nil
}