mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 02:18:08 +08:00
feat: extend license enforcement to webapp API endpoints
Extend license middleware to also block webapp API (/api/*) when enterprise license is expired/inactive/lost. Changes: - Check both /console/api and /api endpoints - Add webapp-specific exempt paths: - /api/passport (webapp authentication) - /api/login, /api/logout, /api/oauth - /api/forgot-password - /api/system-features (webapp needs this to check license status) This ensures both console users and webapp users are blocked when license expires, maintaining consistent enforcement across all APIs.
This commit is contained in:
@ -34,47 +34,42 @@ def create_flask_app_with_configs() -> DifyApp:
|
|||||||
init_request_context()
|
init_request_context()
|
||||||
RecyclableContextVar.increment_thread_recycles()
|
RecyclableContextVar.increment_thread_recycles()
|
||||||
|
|
||||||
# Enterprise license validation for console API endpoints
|
# Enterprise license validation for API endpoints (both console and webapp)
|
||||||
if dify_config.ENTERPRISE_ENABLED and request.path.startswith("/console/api"):
|
# When license expires, ONLY allow features API - everything else is blocked
|
||||||
# Skip license check for auth-related endpoints and system endpoints
|
if dify_config.ENTERPRISE_ENABLED:
|
||||||
exempt_paths = [
|
is_console_api = request.path.startswith("/console/api")
|
||||||
"/console/api/login",
|
is_webapp_api = request.path.startswith("/api") and not is_console_api
|
||||||
"/console/api/logout",
|
|
||||||
"/console/api/oauth",
|
|
||||||
"/console/api/setup",
|
|
||||||
"/console/api/init",
|
|
||||||
"/console/api/forgot-password",
|
|
||||||
"/console/api/email-code-login",
|
|
||||||
"/console/api/activation",
|
|
||||||
"/console/api/data-source-oauth",
|
|
||||||
"/console/api/features", # Allow fetching features to show license status
|
|
||||||
]
|
|
||||||
|
|
||||||
# Check if current path is exempt
|
if is_console_api or is_webapp_api:
|
||||||
is_exempt = any(request.path.startswith(path) for path in exempt_paths)
|
# Only exempt features endpoints - block everything else including auth
|
||||||
|
# Admin can access through admin dashboard (separate service)
|
||||||
|
if is_console_api:
|
||||||
|
is_exempt = request.path.startswith("/console/api/features")
|
||||||
|
else: # webapp API
|
||||||
|
is_exempt = request.path.startswith("/api/system-features")
|
||||||
|
|
||||||
if not is_exempt:
|
if not is_exempt:
|
||||||
try:
|
try:
|
||||||
# Check license status
|
# Check license status
|
||||||
system_features = FeatureService.get_system_features(is_authenticated=True)
|
system_features = FeatureService.get_system_features(is_authenticated=True)
|
||||||
if system_features.license.status in [
|
if system_features.license.status in [
|
||||||
LicenseStatus.INACTIVE,
|
LicenseStatus.INACTIVE,
|
||||||
LicenseStatus.EXPIRED,
|
LicenseStatus.EXPIRED,
|
||||||
LicenseStatus.LOST,
|
LicenseStatus.LOST,
|
||||||
]:
|
]:
|
||||||
# Raise UnauthorizedAndForceLogout to trigger frontend reload and logout
|
# Raise UnauthorizedAndForceLogout to trigger frontend reload and logout
|
||||||
# Frontend checks code === 'unauthorized_and_force_logout' and calls location.reload()
|
# Frontend checks code === 'unauthorized_and_force_logout' and calls location.reload()
|
||||||
raise UnauthorizedAndForceLogout(
|
raise UnauthorizedAndForceLogout(
|
||||||
f"Enterprise license is {system_features.license.status.value}. "
|
f"Enterprise license is {system_features.license.status.value}. "
|
||||||
"Please contact your administrator."
|
"Please contact your administrator."
|
||||||
)
|
)
|
||||||
except UnauthorizedAndForceLogout:
|
except UnauthorizedAndForceLogout:
|
||||||
# Re-raise to let Flask error handler convert to proper JSON response
|
# Re-raise to let Flask error handler convert to proper JSON response
|
||||||
raise
|
raise
|
||||||
except Exception:
|
except Exception:
|
||||||
# If license check fails, log but don't block the request
|
# If license check fails, log but don't block the request
|
||||||
# This prevents service disruption if enterprise API is temporarily unavailable
|
# This prevents service disruption if enterprise API is temporarily unavailable
|
||||||
logger.exception("Failed to check enterprise license status")
|
logger.exception("Failed to check enterprise license status")
|
||||||
|
|
||||||
# add after request hook for injecting trace headers from OpenTelemetry span context
|
# add after request hook for injecting trace headers from OpenTelemetry span context
|
||||||
# Only adds headers when OTEL is enabled and has valid context
|
# Only adds headers when OTEL is enabled and has valid context
|
||||||
|
|||||||
Reference in New Issue
Block a user