Skip to content

Security Decorators

The decorators module provides route-level security controls for individual Django views.


Main Decorator Class

. SecurityDecorator

guard_core.decorators.SecurityDecorator(config)

Bases: BaseSecurityDecorator, AccessControlMixin, RateLimitingMixin, BehavioralMixin, AuthenticationMixin, ContentFilteringMixin, AdvancedMixin

Source code in guard_core/decorators/base.py
def __init__(self, config: SecurityConfig) -> None:
    self.config = config
    self._route_configs: dict[str, RouteConfig] = {}
    self.behavior_tracker = BehaviorTracker(config)
    self.agent_handler: Any = None
from djangoapi_guard import SecurityConfig
from djangoapi_guard import SecurityDecorator

config = SecurityConfig()
guard_deco = SecurityDecorator(config)

@guard_deco.rate_limit(requests=5, window=300)
@guard_deco.require_ip(whitelist=["10.0.0.0/8"])
def sensitive_endpoint(request):
    return JsonResponse({"data": "sensitive"})

Mixin Classes

. AccessControlMixin

guard_core.decorators.access_control.AccessControlMixin

Bases: BaseSecurityMixin

allow_countries(countries)

Source code in guard_core/decorators/access_control.py
def allow_countries(
    self, countries: list[str]
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        route_config.whitelist_countries = countries
        return self._apply_route_config(func)

    return decorator

block_clouds(providers=None)

Source code in guard_core/decorators/access_control.py
def block_clouds(
    self, providers: list[str] | None = None
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        if providers is None:
            route_config.block_cloud_providers = {"AWS", "GCP", "Azure"}
        else:
            route_config.block_cloud_providers = set(providers)
        return self._apply_route_config(func)

    return decorator

block_countries(countries)

Source code in guard_core/decorators/access_control.py
def block_countries(
    self, countries: list[str]
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        route_config.blocked_countries = countries
        return self._apply_route_config(func)

    return decorator

bypass(checks)

Source code in guard_core/decorators/access_control.py
def bypass(
    self, checks: list[str]
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        route_config.bypassed_checks.update(checks)
        return self._apply_route_config(func)

    return decorator

require_ip(whitelist=None, blacklist=None)

Source code in guard_core/decorators/access_control.py
def require_ip(
    self,
    whitelist: list[str] | None = None,
    blacklist: list[str] | None = None,
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        if whitelist:
            route_config.ip_whitelist = whitelist
        if blacklist:
            route_config.ip_blacklist = blacklist
        return self._apply_route_config(func)

    return decorator
  • @guard_deco.require_ip(whitelist=[], blacklist=[]) - IP address filtering
  • @guard_deco.block_countries(countries=[]) - Block specific countries
  • @guard_deco.allow_countries(countries=[]) - Allow only specific countries
  • @guard_deco.block_clouds(providers=[]) - Block cloud provider IPs
  • @guard_deco.bypass(checks=[]) - Bypass specific security checks

. AuthenticationMixin

guard_core.decorators.authentication.AuthenticationMixin

Bases: BaseSecurityMixin

api_key_auth(header_name='X-API-Key')

Source code in guard_core/decorators/authentication.py
def api_key_auth(
    self, header_name: str = "X-API-Key"
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        route_config.api_key_required = True
        route_config.required_headers[header_name] = "required"
        return self._apply_route_config(func)

    return decorator

require_auth(type='bearer')

Source code in guard_core/decorators/authentication.py
def require_auth(
    self, type: str = "bearer"
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        route_config.auth_required = type
        return self._apply_route_config(func)

    return decorator

require_headers(headers)

Source code in guard_core/decorators/authentication.py
def require_headers(
    self, headers: dict[str, str]
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        route_config.required_headers.update(headers)
        return self._apply_route_config(func)

    return decorator

require_https()

Source code in guard_core/decorators/authentication.py
def require_https(self) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        route_config.require_https = True
        return self._apply_route_config(func)

    return decorator
  • @guard_deco.require_https() - Force HTTPS
  • @guard_deco.require_auth(type="bearer") - Require authentication
  • @guard_deco.api_key_auth(header_name="X-API-Key") - API key authentication
  • @guard_deco.require_headers(headers={}) - Require specific headers

. RateLimitingMixin

guard_core.decorators.rate_limiting.RateLimitingMixin

Bases: BaseSecurityMixin

geo_rate_limit(limits)

Source code in guard_core/decorators/rate_limiting.py
def geo_rate_limit(
    self, limits: dict[str, tuple[int, int]]
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        route_config.geo_rate_limits = limits
        return self._apply_route_config(func)

    return decorator

rate_limit(requests, window=60)

Source code in guard_core/decorators/rate_limiting.py
def rate_limit(
    self, requests: int, window: int = 60
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        route_config.rate_limit = requests
        route_config.rate_limit_window = window
        return self._apply_route_config(func)

    return decorator
  • @guard_deco.rate_limit(requests=10, window=60) - Basic rate limiting
  • @guard_deco.geo_rate_limit(limits={}) - Geographic rate limiting

. BehavioralMixin

guard_core.decorators.behavioral.BehavioralMixin

Bases: BaseSecurityMixin

behavior_analysis(rules)

Source code in guard_core/decorators/behavioral.py
def behavior_analysis(
    self, rules: list[BehaviorRule]
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        route_config.behavior_rules.extend(rules)
        return self._apply_route_config(func)

    return decorator

return_monitor(pattern, max_occurrences, window=86400, action='ban')

Source code in guard_core/decorators/behavioral.py
def return_monitor(
    self,
    pattern: str,
    max_occurrences: int,
    window: int = 86400,
    action: Literal["ban", "log", "throttle", "alert"] = "ban",
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)

        rule = BehaviorRule(
            rule_type="return_pattern",
            threshold=max_occurrences,
            window=window,
            pattern=pattern,
            action=action,
        )
        route_config.behavior_rules.append(rule)
        return self._apply_route_config(func)

    return decorator

suspicious_frequency(max_frequency, window=300, action='ban')

Source code in guard_core/decorators/behavioral.py
def suspicious_frequency(
    self,
    max_frequency: float,
    window: int = 300,
    action: Literal["ban", "log", "throttle", "alert"] = "ban",
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        max_calls = int(max_frequency * window)

        rule = BehaviorRule(
            rule_type="frequency",
            threshold=max_calls,
            window=window,
            action=action,
        )
        route_config.behavior_rules.append(rule)
        return self._apply_route_config(func)

    return decorator

usage_monitor(max_calls, window=3600, action='ban')

Source code in guard_core/decorators/behavioral.py
def usage_monitor(
    self,
    max_calls: int,
    window: int = 3600,
    action: Literal["ban", "log", "throttle", "alert"] = "ban",
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)

        rule = BehaviorRule(
            rule_type="usage", threshold=max_calls, window=window, action=action
        )
        route_config.behavior_rules.append(rule)
        return self._apply_route_config(func)

    return decorator
  • @guard_deco.usage_monitor(max_calls, window, action) - Monitor endpoint usage
  • @guard_deco.return_monitor(pattern, max_occurrences, window, action) - Monitor return patterns
  • @guard_deco.behavior_analysis(rules=[]) - Apply multiple behavioral rules

. ContentFilteringMixin

guard_core.decorators.content_filtering.ContentFilteringMixin

Bases: BaseSecurityMixin

block_user_agents(patterns)

Source code in guard_core/decorators/content_filtering.py
def block_user_agents(
    self, patterns: list[str]
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        route_config.blocked_user_agents.extend(patterns)
        return self._apply_route_config(func)

    return decorator

content_type_filter(allowed_types)

Source code in guard_core/decorators/content_filtering.py
def content_type_filter(
    self, allowed_types: list[str]
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        route_config.allowed_content_types = allowed_types
        return self._apply_route_config(func)

    return decorator

custom_validation(validator)

Source code in guard_core/decorators/content_filtering.py
def custom_validation(
    self,
    validator: Callable[[GuardRequest], Awaitable[GuardResponse | None]],
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        route_config.custom_validators.append(validator)
        return self._apply_route_config(func)

    return decorator

max_request_size(size_bytes)

Source code in guard_core/decorators/content_filtering.py
def max_request_size(
    self, size_bytes: int
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        route_config.max_request_size = size_bytes
        return self._apply_route_config(func)

    return decorator

require_referrer(allowed_domains)

Source code in guard_core/decorators/content_filtering.py
def require_referrer(
    self, allowed_domains: list[str]
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        route_config.require_referrer = allowed_domains
        return self._apply_route_config(func)

    return decorator
  • @guard_deco.block_user_agents(patterns=[]) - Block user agent patterns
  • @guard_deco.content_type_filter(allowed_types=[]) - Filter content types
  • @guard_deco.max_request_size(size_bytes) - Limit request size
  • @guard_deco.require_referrer(allowed_domains=[]) - Require specific referrers
  • @guard_deco.custom_validation(validator) - Add custom validation logic

. AdvancedMixin

guard_core.decorators.advanced.AdvancedMixin

Bases: BaseSecurityMixin

honeypot_detection(trap_fields)

Source code in guard_core/decorators/advanced.py
def honeypot_detection(
    self, trap_fields: list[str]
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        async def honeypot_validator(
            request: GuardRequest,
        ) -> GuardResponse | None:
            def _has_trap_field_filled(data: dict[str, Any]) -> bool:
                return any(field in data and data[field] for field in trap_fields)

            async def _validate_form_data() -> GuardResponse | None:
                try:
                    raw = (await request.body()).decode()
                    parsed = parse_qs(raw)
                    flat = {k: v[0] for k, v in parsed.items() if v}
                    if _has_trap_field_filled(flat):
                        return _SimpleResponse("Forbidden", 403)
                except Exception:
                    pass
                return None

            async def _validate_json_data() -> GuardResponse | None:
                try:
                    raw = (await request.body()).decode()
                    json_data = json.loads(raw)
                    if _has_trap_field_filled(json_data):
                        return _SimpleResponse("Forbidden", 403)
                except Exception:
                    pass
                return None

            if request.method not in ["POST", "PUT", "PATCH"]:
                return None

            content_type = request.headers.get("content-type", "")

            if "application/x-www-form-urlencoded" in content_type:
                return await _validate_form_data()
            elif "application/json" in content_type:
                return await _validate_json_data()

            return None

        route_config = self._ensure_route_config(func)
        route_config.custom_validators.append(honeypot_validator)
        return self._apply_route_config(func)

    return decorator

suspicious_detection(enabled=True)

Source code in guard_core/decorators/advanced.py
def suspicious_detection(
    self, enabled: bool = True
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        route_config.enable_suspicious_detection = enabled
        return self._apply_route_config(func)

    return decorator

time_window(start_time, end_time, timezone='UTC')

Source code in guard_core/decorators/advanced.py
def time_window(
    self, start_time: str, end_time: str, timezone: str = "UTC"
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        route_config = self._ensure_route_config(func)
        route_config.time_restrictions = {
            "start": start_time,
            "end": end_time,
            "timezone": timezone,
        }
        return self._apply_route_config(func)

    return decorator
  • @guard_deco.time_window(start_time, end_time, timezone) - Time-based access control
  • @guard_deco.suspicious_detection(enabled=True) - Toggle suspicious pattern detection
  • @guard_deco.honeypot_detection(trap_fields=[]) - Detect bots using honeypot fields

Configuration Priority

  1. Decorator Settings (highest priority)
  2. Global Middleware Settings
  3. Default Settings (lowest priority)