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 ". // 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)) }) }