77from uuid import uuid4
88
99from django .urls import reverse
10- from reactpy import component , hooks , html
10+ from reactpy import component , hooks
1111
1212from reactpy_django .javascript_components import HttpRequest
13- from reactpy_django .models import SynchronizeSession
13+ from reactpy_django .models import AuthToken
1414
1515if TYPE_CHECKING :
1616 from django .contrib .sessions .backends .base import SessionBase
@@ -39,13 +39,13 @@ async def rerender():
3939@component
4040def session_manager ():
4141 """This component can force the client (browser) to switch HTTP sessions,
42- making it match the websocket session.
42+ making it match the websocket session, by using a authentication token .
4343
4444 Used to force persistent authentication between Django's websocket and HTTP stack."""
4545 from reactpy_django import config
4646
4747 synchronize_requested , set_synchronize_requested = hooks .use_state (False )
48- uuid = hooks .use_ref ("" )
48+ token = hooks .use_ref ("" )
4949 scope = hooks .use_connection ().scope
5050
5151 @hooks .use_effect (dependencies = [])
@@ -61,33 +61,32 @@ async def synchronize_session_watchdog():
6161 This effect will automatically be cancelled if the session is successfully
6262 switched (via effect dependencies)."""
6363 if synchronize_requested :
64- await asyncio .sleep (config .REACTPY_AUTH_SYNC_TIMEOUT + 0.1 )
64+ await asyncio .sleep (config .REACTPY_AUTH_TOKEN_TIMEOUT + 0.1 )
6565 await asyncio .to_thread (
6666 _logger .warning ,
67- f"Client did not switch sessions within { config .REACTPY_AUTH_SYNC_TIMEOUT } (REACTPY_AUTH_SYNC_TIMEOUT ) seconds." ,
67+ f"Client did not switch sessions within { config .REACTPY_AUTH_TOKEN_TIMEOUT } (REACTPY_AUTH_TOKEN_TIMEOUT ) seconds." ,
6868 )
6969 set_synchronize_requested (False )
7070
7171 async def synchronize_session ():
72- """Event that can command the client to switch HTTP sessions (to match the websocket sessions )."""
72+ """Event that can command the client to switch HTTP sessions (to match the websocket session )."""
7373 session : SessionBase | None = scope .get ("session" )
7474 if not session or not session .session_key :
7575 return
7676
77- # Delete any sessions currently associated with the previous UUID.
78- # This exists to fix scenarios where...
79- # 1) Login is called multiple times before the first one is completed.
80- # 2) Login was called, but the server failed to respond to the HTTP request.
81- if uuid .current :
82- with contextlib .suppress (SynchronizeSession .DoesNotExist ):
83- obj = await SynchronizeSession .objects .aget (uuid = uuid .current )
77+ # Delete previous token to resolve race conditions where...
78+ # 1. Login was called multiple times before the first one is completed.
79+ # 2. Login was called, but the server failed to respond to the HTTP request.
80+ if token .current :
81+ with contextlib .suppress (AuthToken .DoesNotExist ):
82+ obj = await AuthToken .objects .aget (value = token .current )
8483 await obj .adelete ()
8584
86- # Create a fresh UUID
87- uuid .set_current (str (uuid4 ()))
85+ # Create a fresh token
86+ token .set_current (str (uuid4 ()))
8887
8988 # Begin the process of synchronizing HTTP and websocket sessions
90- obj = await SynchronizeSession .objects .acreate (uuid = uuid .current , session_key = session .session_key )
89+ obj = await AuthToken .objects .acreate (value = token .current , session_key = session .session_key )
9190 await obj .asave ()
9291 set_synchronize_requested (True )
9392
@@ -107,7 +106,7 @@ async def synchronize_session_callback(status_code: int, response: str):
107106 return HttpRequest (
108107 {
109108 "method" : "GET" ,
110- "url" : reverse ("reactpy:session_manager" , args = [uuid .current ]),
109+ "url" : reverse ("reactpy:session_manager" , args = [token .current ]),
111110 "body" : None ,
112111 "callback" : synchronize_session_callback ,
113112 },
0 commit comments