Skip to content

Commit 29cccab

Browse files
committed
REACTPY_AUTO_LOGIN setting
1 parent 09dc565 commit 29cccab

File tree

3 files changed

+43
-20
lines changed

3 files changed

+43
-20
lines changed

CHANGELOG.md

+14-5
Original file line numberDiff line numberDiff line change
@@ -39,20 +39,29 @@ Using the following categories, list your changes in this order:
3939
- ReactPy components can now use SEO compatible rendering!
4040
- `settings.py:REACTPY_PRERENDER` can be set to `True` to enable this behavior by default
4141
- Or, you can enable it on individual components via the template tag: `{% component "..." prerender="True" %}`
42-
- `reactpy_django.components.view_to_iframe` component has been added, which uses an `<iframe>` to render a Django view.
43-
- `reactpy_django.utils.register_iframe` function has been added, which is mandatory to use alongside `reactpy_django.components.view_to_iframe`.
42+
- New components!
43+
- `reactpy_django.components.view_to_iframe` uses an `<iframe>` to render a Django view.
44+
- New utilies!
45+
- `reactpy_django.utils.register_iframe` notifies ReactPy which views are allowed to be used with `view_to_iframe`.
46+
- New decorators!
47+
- `reactpy_django.decorators.user_passes_test` is a similar equivalent to Django's `user_passes_test` decorator, but ours works with ReactPy components.
48+
- New hooks!
49+
- `reactpy_django.hooks.use_user` can be used to access the current user.
50+
- `reactpy_django.hooks.use_user_data` provides a simplified interface for storing user key-value data.
51+
- New settings!
52+
- `REACTPY_AUTO_LOGIN` automatically logs in **pre-authenticated** users that during the initial component WebSocket connection. This is useful to continuously update `last_login` timestamps.
4453

4554
### Changed
4655

47-
- Renamed undocumented utility function `reactpy_django.utils.ComponentPreloader` to `reactpy_django.utils.RootComponentFinder`.
56+
- Renamed undocumented utility function `ComponentPreloader` to `RootComponentFinder`.
4857
- It is now recommended to call `as_view()` when using `view_to_component` or `view_to_iframe` with Class Based Views.
4958
- Thread sensitivity has been enabled in all locations where ORM queries are possible.
5059

5160
### Deprecated
5261

53-
- The `compatibility` argument on `reactpy_django.components.view_to_component` is deprecated. Use `reactpy_django.components.view_to_iframe` instead.
62+
- The `compatibility` argument on `reactpy_django.components.view_to_component` is deprecated. Use `view_to_iframe` instead.
5463
- Using `reactpy_django.components.view_to_component` as a decorator is deprecated. Check the docs on the new suggested usage.
55-
- `reactpy_django.decorators.auth_required` is deprecated. An equivalent to this decorator's default is `@reactpy_django.decorators.user_passes_test(lambda user: user.is_active)`.
64+
- `reactpy_django.decorators.auth_required` is deprecated. An equivalent to this decorator's default is `@user_passes_test(lambda user: user.is_active)`.
5665

5766
## [3.5.1] - 2023-09-07
5867

src/reactpy_django/config.py

+5
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,8 @@
113113
"REACTPY_PRERENDER",
114114
False,
115115
)
116+
REACTPY_AUTO_LOGIN: bool = getattr(
117+
settings,
118+
"REACTPY_AUTO_LOGIN",
119+
True,
120+
)

src/reactpy_django/websocket/consumer.py

+24-15
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88
from concurrent.futures import Future
99
from datetime import timedelta
1010
from threading import Thread
11-
from typing import Any, MutableMapping, Sequence
11+
from typing import TYPE_CHECKING, Any, MutableMapping, Sequence
1212

1313
import dill as pickle
1414
import orjson
15+
from channels.auth import login
1516
from channels.db import database_sync_to_async
1617
from channels.generic.websocket import AsyncJsonWebsocketConsumer
1718
from django.utils import timezone
@@ -23,6 +24,9 @@
2324
from reactpy_django.types import ComponentParams
2425
from reactpy_django.utils import delete_expired_sessions
2526

27+
if TYPE_CHECKING:
28+
from django.contrib.auth.models import AbstractUser
29+
2630
_logger = logging.getLogger(__name__)
2731
backhaul_loop = asyncio.new_event_loop()
2832

@@ -42,23 +46,28 @@ class ReactpyAsyncWebsocketConsumer(AsyncJsonWebsocketConsumer):
4246
async def connect(self) -> None:
4347
"""The browser has connected."""
4448
from reactpy_django import models
45-
from reactpy_django.config import REACTPY_BACKHAUL_THREAD
49+
from reactpy_django.config import (
50+
REACTPY_AUTH_BACKEND,
51+
REACTPY_AUTO_LOGIN,
52+
REACTPY_BACKHAUL_THREAD,
53+
)
4654

4755
await super().connect()
4856

49-
# Warn for missing features
50-
if self.scope.get("user") is None:
51-
await asyncio.to_thread(
52-
_logger.debug,
53-
"ReactPy websocket is missing Auth Middleware! "
54-
"User will not be accessible within hooks!",
55-
)
56-
if not self.scope.get("session"):
57-
await asyncio.to_thread(
58-
_logger.debug,
59-
"ReactPy websocket is missing Session Middleware! "
60-
"Sessions will not be accessible within hooks!",
61-
)
57+
user: AbstractUser = self.scope.get("user")
58+
if REACTPY_AUTO_LOGIN and user and user.is_authenticated:
59+
try:
60+
await login(self.scope, user, backend=REACTPY_AUTH_BACKEND)
61+
except Exception:
62+
await asyncio.to_thread(
63+
_logger.exception, "ReactPy websocket authentication has failed!"
64+
)
65+
try:
66+
await database_sync_to_async(self.scope["session"].save)()
67+
except Exception:
68+
await asyncio.to_thread(
69+
_logger.exception, "ReactPy has failed to save scope['session']!"
70+
)
6271

6372
# Start the component dispatcher
6473
self.dispatcher: Future | asyncio.Task

0 commit comments

Comments
 (0)