Initial commit: GovAI 政务AI平台
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
// extractIP returns a clean IP without port. Falls back to "" so the INET
|
||||
// column can take NULL via $5 when the value is empty.
|
||||
func extractIP(r *http.Request) any {
|
||||
addr := r.RemoteAddr
|
||||
if host, _, err := net.SplitHostPort(addr); err == nil {
|
||||
addr = host
|
||||
}
|
||||
if addr == "" {
|
||||
return nil
|
||||
}
|
||||
return addr
|
||||
}
|
||||
|
||||
// AuditLog records API access to the audit_logs table for important operations.
|
||||
func AuditLog(pool *pgxpool.Pool) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
next.ServeHTTP(w, r)
|
||||
|
||||
// Only audit write operations
|
||||
if r.Method == "GET" || r.Method == "OPTIONS" {
|
||||
return
|
||||
}
|
||||
|
||||
userID := GetUserID(r.Context())
|
||||
if userID.String() == "00000000-0000-0000-0000-000000000000" {
|
||||
return
|
||||
}
|
||||
|
||||
details, _ := json.Marshal(map[string]string{
|
||||
"method": r.Method,
|
||||
"path": r.URL.Path,
|
||||
})
|
||||
|
||||
ip := extractIP(r)
|
||||
ua := r.UserAgent()
|
||||
method := r.Method
|
||||
path := r.URL.Path
|
||||
|
||||
go func() {
|
||||
_, _ = pool.Exec(context.Background(),
|
||||
`INSERT INTO audit_logs (user_id, action, resource_type, resource_id, details, ip_address, user_agent)
|
||||
VALUES ($1, $2, $3, NULL, $4, $5, $6)`,
|
||||
userID,
|
||||
method+"."+path,
|
||||
"api",
|
||||
details,
|
||||
ip,
|
||||
ua,
|
||||
)
|
||||
}()
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user