Files
W04_048_Zagar_Database/internal/middleware/require_auth.go
T

78 lines
1.9 KiB
Go

package middleware
import (
"context"
"net/http"
"strings"
"5803025048/W04/internal/models"
)
type contextKey string
const UserIDKey contextKey = "user_id"
// GetUserID mengambil user id yang disimpan RequireAuth di context request.
func GetUserID(ctx context.Context) string {
if val, ok := ctx.Value(UserIDKey).(string); ok {
return val
}
return ""
}
// SessionLookup adalah interface kecil yang dibutuhkan middleware:
// mencari session (dan user id-nya) dari sebuah token.
// *store.SessionStore memenuhi interface ini tanpa perubahan.
type SessionLookup interface {
Get(ctx context.Context, token string) (*models.Session, error)
}
type AuthMiddleware struct {
sessions SessionLookup
}
func NewAuthMiddleware(sessions SessionLookup) *AuthMiddleware {
return &AuthMiddleware{sessions: sessions}
}
const bearerPrefix = "Bearer "
// BearerToken mengambil token dari header "Authorization: Bearer <token>".
// Mengembalikan false jika header tidak ada, skema bukan Bearer, atau token kosong.
func BearerToken(r *http.Request) (string, bool) {
h := r.Header.Get("Authorization")
if len(h) <= len(bearerPrefix) || !strings.EqualFold(h[:len(bearerPrefix)], bearerPrefix) {
return "", false
}
token := strings.TrimSpace(h[len(bearerPrefix):])
if token == "" {
return "", false
}
return token, true
}
func unauthorized(w http.ResponseWriter) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
_, _ = w.Write([]byte(`{"error":"Unauthorized"}` + "\n"))
}
func (m *AuthMiddleware) RequireAuth(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token, ok := BearerToken(r)
if !ok {
unauthorized(w)
return
}
session, err := m.sessions.Get(r.Context(), token)
if err != nil || session == nil {
unauthorized(w)
return
}
ctx := context.WithValue(r.Context(), UserIDKey, session.UserID)
next.ServeHTTP(w, r.WithContext(ctx))
})
}