mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-11-09 05:24:49 +09:00
Introduce programmatic API features and observability: add API Key management, API usage analytics, webhook event subscriptions, and OpenAPI docs. New models (ApiKey, ApiUsageLog, ApiUsageSummary, EventSubscription, EventDelivery), services (api_analytics, api_key, event, openapi), and blueprints (/api-keys, /api-analytics, /event-subscriptions, /docs) were added and registered in create_app. Middleware for API key authentication, buffered analytics logging (with a flush thread), and enhanced rate limiting (custom key function and response headers) were implemented; RBAC was updated to accept API key auth via an auth_required decorator. Background threads for hourly aggregation and event retry were added; security CSP updated to allow resources for Swagger UI. Frontend settings UI and styles were added/updated for API keys and webhooks, and requirements were updated.
37 lines
1.2 KiB
Python
37 lines
1.2 KiB
Python
"""API Key authentication middleware."""
|
|
from flask import g, request, jsonify
|
|
|
|
|
|
def register_api_key_auth(app):
|
|
"""Register API key authentication as a before_request handler."""
|
|
|
|
@app.before_request
|
|
def authenticate_api_key():
|
|
"""Check for X-API-Key header and validate."""
|
|
api_key_header = request.headers.get('X-API-Key')
|
|
|
|
if not api_key_header:
|
|
return # No API key provided, fall through to JWT auth
|
|
|
|
from app.services.api_key_service import ApiKeyService
|
|
api_key = ApiKeyService.validate_key(api_key_header)
|
|
|
|
if not api_key:
|
|
return jsonify({'error': 'Invalid or expired API key'}), 401
|
|
|
|
# Record usage
|
|
ip_address = request.remote_addr
|
|
if request.headers.get('X-Forwarded-For'):
|
|
ip_address = request.headers.get('X-Forwarded-For').split(',')[0].strip()
|
|
elif request.headers.get('X-Real-IP'):
|
|
ip_address = request.headers.get('X-Real-IP')
|
|
|
|
api_key.record_usage(ip_address)
|
|
|
|
from app import db
|
|
db.session.commit()
|
|
|
|
# Store in g for downstream use
|
|
g.api_key = api_key
|
|
g.api_key_user = api_key.user
|