django-axes/axes/middleware.py

68 lines
2.5 KiB
Python
Raw Normal View History

2019-04-27 14:55:28 +00:00
from typing import Callable
2023-12-13 04:35:22 +00:00
from asgiref.sync import iscoroutinefunction, markcoroutinefunction, sync_to_async
from django.conf import settings
2022-04-26 13:09:10 +00:00
from django.http import HttpRequest, HttpResponse
2021-01-04 17:02:04 +00:00
from axes.helpers import get_lockout_response
class AxesMiddleware:
"""
2019-05-01 15:28:29 +00:00
Middleware that calculates necessary HTTP request attributes for attempt monitoring
and maps lockout signals into readable HTTP 403 Forbidden responses.
2020-10-07 16:19:54 +00:00
If a project uses ``django rest framework`` then the middleware updates the
2020-10-07 16:16:21 +00:00
request and checks whether the limit has been exceeded. It's needed only
for integration with DRF because it uses its own request object.
This middleware recognizes a logout monitoring flag in the request and
2019-05-01 15:28:29 +00:00
and uses the ``axes.helpers.get_lockout_response`` handler for returning
customizable and context aware lockout message to the end user if necessary.
2019-05-01 15:28:29 +00:00
To customize the lockout handling behaviour further, you can subclass this middleware
and change the ``__call__`` method to your own liking.
2019-05-01 15:28:29 +00:00
Please see the following configuration flags before customizing this handler:
- ``AXES_LOCKOUT_TEMPLATE``,
- ``AXES_LOCKOUT_URL``,
- ``AXES_COOLOFF_MESSAGE``, and
- ``AXES_PERMALOCK_MESSAGE``.
"""
2023-12-13 04:35:22 +00:00
async_capable = True
sync_capable = True
2022-04-26 13:09:10 +00:00
def __init__(self, get_response: Callable) -> None:
self.get_response = get_response
2023-12-13 04:35:22 +00:00
if iscoroutinefunction(self.get_response):
markcoroutinefunction(self)
2022-04-26 13:09:10 +00:00
def __call__(self, request: HttpRequest) -> HttpResponse:
2023-12-13 04:35:22 +00:00
# Exit out to async mode, if needed
if iscoroutinefunction(self):
return self.__acall__(request)
2023-12-13 04:35:22 +00:00
response = self.get_response(request)
if settings.AXES_ENABLED:
if getattr(request, "axes_locked_out", None):
2021-10-09 10:51:14 +00:00
credentials = getattr(request, "axes_credentials", None)
response = get_lockout_response(request, response, credentials) # type: ignore
return response
2023-12-13 04:35:22 +00:00
async def __acall__(self, request: HttpRequest) -> HttpResponse:
response = await self.get_response(request)
if settings.AXES_ENABLED:
if getattr(request, "axes_locked_out", None):
credentials = getattr(request, "axes_credentials", None)
response = await sync_to_async(
2023-12-27 10:40:23 +00:00
get_lockout_response, thread_sensitive=True
2026-02-11 19:54:13 +00:00
)(
request, credentials
) # type: ignore
2023-12-13 04:35:22 +00:00
return response