1
0
Эх сурвалжийг харах

extracted auth code into derived page

Rodja Trappe 1 жил өмнө
parent
commit
c616cae50d

+ 10 - 93
examples/descope_auth/main.py

@@ -1,107 +1,24 @@
 #!/usr/bin/env python3
 
-import logging
-import os
+import icecream
+from secure_page import descope_id, logout, secure_page
 
-from descope import REFRESH_SESSION_TOKEN_NAME, SESSION_TOKEN_NAME, AuthException, DeliveryMethod, DescopeClient
-from fastapi import Request
-from fastapi.responses import RedirectResponse
-from icecream import ic
-from starlette.middleware.base import BaseHTTPMiddleware
+from nicegui import ui
 
-import nicegui.globals
-from nicegui import Client, app, events, ui
+icecream.install()
 
-descope_id = os.environ.get('DESCOPE_ID', '')
-try:
-    descope_client = DescopeClient(project_id=descope_id)
-except Exception as error:
-    print("failed to initialize. Error:")
-    print(error)
 
-
-def validate_session():
-    return
-    # Fetch session token from HTTP Authorization Header
-    session_token = "xxxx"
-
-    try:
-        jwt_response = descope_client.validate_session(session_token=session_token)
-        print("Successfully validated user session:")
-        print(jwt_response)
-    except Exception:
-        logging.exception("Could not validate user session.")
-
-
-class AuthMiddleware(BaseHTTPMiddleware):
-    """This middleware restricts access to all NiceGUI pages.
-
-    It redirects the user to the login page if they are not authenticated.
-    """
-
-    async def dispatch(self, request: Request, call_next):
-        if not app.storage.user.get('authenticated', False):
-            if request.url.path in nicegui.globals.page_routes.values() and request.url.path not in unrestricted_page_routes:
-                app.storage.user['referrer_path'] = request.url.path  # remember where the user wanted to go
-                return RedirectResponse('/login')
-        return await call_next(request)
-
-
-app.add_middleware(AuthMiddleware)
-
-unrestricted_page_routes = {'/login'}
-
-
-def verify(token: str):
-    ic()
-    try:
-        jwt_response = descope_client.validate_session(session_token=token)
-        ic(jwt_response)
-        return True
-    except Exception:
-        logging.exception("Could not validate user session.")
-        ui.notify('Wrong username or password', type='negative')
-        return False
-
-
-@ui.page('/login')
-async def login(client: Client):
-    ui.add_head_html('<script src="https://unpkg.com/@descope/web-js-sdk/dist/index.umd.js"></script>')
-    ui.add_body_html('''
-        <script>
-            const sdk = Descope({ projectId: \'''' + descope_id + '''\', persistTokens: true, autoRefresh: true });
-            const sessionToken = sdk.getSessionToken()
-        </script>                 
-    ''')
-
-    await client.connected()
-    token = await ui.run_javascript('''
-            if (sessionToken && !sdk.isJwtExpired(sessionToken)) {
-                return sessionToken;
-            } else {
-                return null;
-            }
-    ''')
+@secure_page('/login')
+def login():
     with ui.card().classes('w-96 mx-auto'):
-        if token and verify(token):
-            app.storage.user['authenticated'] = True
-            ui.open('/')
-        else:
-            ui.add_head_html('<script src="https://unpkg.com/@descope/web-component/dist/index.js"></script>')
-            ui.element('descope-wc').props(f'project-id="{descope_id}" flow-id="sign-up-or-in"') \
-                .on('success', lambda: ui.open('/'))
+        ui.element('descope-wc').props(f'project-id="{descope_id}" flow-id="sign-up-or-in"') \
+            .on('success', lambda: ui.open('/'))
 
 
-@ui.page('/')
+@secure_page('/')
 def home():
-    ui.add_body_html('''
-        <script src="https://unpkg.com/@descope/web-js-sdk/dist/index.umd.js"></script>
-        <script>
-            sdk.refresh()
-        </script>                 
-    ''')
-
     ui.label('Welcome!')
+    ui.button('Logout', on_click=logout)
 
 
 ui.run(storage_secret='THIS_NEEDS_TO_BE_CHANGED')

+ 64 - 0
examples/descope_auth/secure_page.py

@@ -0,0 +1,64 @@
+import logging
+import os
+from typing import Any, Callable
+
+from descope import REFRESH_SESSION_TOKEN_NAME, SESSION_TOKEN_NAME, AuthException, DeliveryMethod, DescopeClient
+
+from nicegui import Client, app, ui
+
+descope_id = os.environ.get('DESCOPE_ID', '')
+
+try:
+    descope_client = DescopeClient(project_id=descope_id)
+except Exception as error:
+    print("failed to initialize. Error:")
+    print(error)
+
+
+async def logout():
+    ic(await ui.run_javascript('return await sdk.logout()', respond=True))
+    ui.open('/login')
+
+
+def verify(token: str):
+    try:
+        jwt_response = descope_client.validate_session(session_token=token)
+        app.storage.user['session_token'] = token
+        return True
+    except Exception:
+        app.storage.user['session_token'] = None
+        logging.exception("Could not validate user session.")
+        ui.notify('Wrong username or password', type='negative')
+        return False
+
+
+class secure_page(ui.page):
+
+    def __init__(self, path):
+        super().__init__(path)
+
+    def __call__(self, func: Callable[..., Any]) -> Callable[..., Any]:
+        async def content(client: Client):
+            ui.add_head_html('<script src="https://unpkg.com/@descope/web-component@latest/dist/index.js"></script>')
+            ui.add_head_html('<script src="https://unpkg.com/@descope/web-js-sdk@latest/dist/index.umd.js"></script>')
+            ui.add_body_html('''
+                <script>
+                    const sdk = Descope({ projectId: \'''' + descope_id + '''\', persistTokens: true, autoRefresh: true });
+                    const sessionToken = sdk.getSessionToken()
+                </script>                 
+            ''')
+            await client.connected()
+            token = await ui.run_javascript('return sessionToken && !sdk.isJwtExpired(sessionToken) ? sessionToken : null;')
+            if token and verify(token):
+                if self.path == '/login':
+                    await ui.run_javascript('sdk.refresh()', respond=False)
+                    ui.open('/')
+                else:
+                    func()
+            else:
+                if self.path != '/login':
+                    ui.open('/login')
+                else:
+                    func()
+
+        return super().__call__(content)