prototype for authentication
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
from fastapi.responses import RedirectResponse
|
||||
from nicegui import APIRouter, app, ui
|
||||
|
||||
|
||||
#TODO
|
||||
passwords = {"a": "a", "b": "b", "c": "c"}
|
||||
pgroups = {"a": {"p11111", "p22222"}, "b": {"p33333", "p44444"}}
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.page("/login")
|
||||
def login(redirect_to: str = "/") -> RedirectResponse | None:
|
||||
if app.storage.user.get("authenticated", False):
|
||||
return RedirectResponse("/")
|
||||
|
||||
def try_login(): # local function to avoid passing username and password as arguments
|
||||
if not username.value:
|
||||
ui.notify("Missing username", color="negative")
|
||||
focus(username)
|
||||
return
|
||||
|
||||
if not password.value:
|
||||
focus(password)
|
||||
return
|
||||
|
||||
if passwords.get(username.value) != password.value:
|
||||
ui.notify("Wrong username or password", color="negative")
|
||||
return
|
||||
|
||||
app.storage.user.update(
|
||||
username=username.value,
|
||||
authenticated=True,
|
||||
pgroups=list(pgroups.get(username.value, set()))
|
||||
)
|
||||
|
||||
ui.navigate.to(redirect_to) # go back to where the user wanted to go
|
||||
|
||||
with ui.card().classes("absolute-center items-stretch"):
|
||||
ui.image("icon.png")
|
||||
username = ui.input("Username").props("autofocus")
|
||||
password = ui.input("Password", password=True, password_toggle_button=True)
|
||||
username.on("keydown.enter", try_login)
|
||||
password.on("keydown.enter", try_login)
|
||||
ui.button("log in", icon="login", on_click=try_login)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def focus(element):
|
||||
ui.run_javascript(f"getElement({element.id}).$refs.qRef.focus()")
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
from nicegui import app, ui
|
||||
|
||||
|
||||
def logout():
|
||||
app.storage.user.clear()
|
||||
ui.navigate.to("/login")
|
||||
|
||||
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
from fastapi import Request
|
||||
from fastapi.responses import RedirectResponse
|
||||
from nicegui import app
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
|
||||
|
||||
unrestricted_page_routes = {"/login"}
|
||||
|
||||
|
||||
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):
|
||||
path = request.url.path
|
||||
|
||||
if (
|
||||
app.storage.user.get("authenticated", False)
|
||||
or path in unrestricted_page_routes
|
||||
or path.startswith("/_nicegui")
|
||||
):
|
||||
return await call_next(request)
|
||||
|
||||
return RedirectResponse(f"/login?redirect_to={path}")
|
||||
|
||||
|
||||
|
||||
Executable
+62
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from nicegui import app, ui
|
||||
|
||||
from auth.login import router as login_router
|
||||
from auth.logout import logout
|
||||
from auth.mw import AuthMiddleware
|
||||
|
||||
|
||||
app.include_router(login_router)
|
||||
app.add_middleware(AuthMiddleware)
|
||||
|
||||
|
||||
@ui.page("/")
|
||||
def main_page():
|
||||
with ui.column().classes("absolute-center items-center"):
|
||||
username = app.storage.user.get("username", "unknown user")
|
||||
ui.label(f"Hello {username}!").classes("text-2xl")
|
||||
ui.button("log out", icon="logout", on_click=logout)
|
||||
|
||||
pgroups = app.storage.user.get("pgroups", set())
|
||||
ui.select(
|
||||
label="pgroup",
|
||||
options=sorted(pgroups),
|
||||
with_input=True,
|
||||
on_change=lambda e: ui.navigate.to(e.value)
|
||||
)
|
||||
|
||||
|
||||
|
||||
#TODO: the below is a dummy
|
||||
|
||||
from typing import Annotated
|
||||
from fastapi import Path
|
||||
|
||||
PGroup = Annotated[str, Path(pattern=r"^p\d{5}$")]
|
||||
|
||||
|
||||
@ui.page("/{pgroup}")
|
||||
def table(pgroup: PGroup):
|
||||
pgroups = app.storage.user.get("pgroups", set())
|
||||
if pgroup in pgroups:
|
||||
table_show(pgroup)
|
||||
else:
|
||||
table_deny(pgroup)
|
||||
|
||||
def table_show(pgroup):
|
||||
with ui.column().classes("absolute-center items-center gap-8"):
|
||||
ui.icon("sym_o_thumb_up", size="xl")
|
||||
ui.label(f"{pgroup} erlaubt!").classes("text-2xl")
|
||||
|
||||
def table_deny(pgroup):
|
||||
with ui.column().classes("absolute-center items-center gap-8"):
|
||||
ui.icon("sym_o_front_hand", size="xl")
|
||||
ui.label(f"{pgroup} verboten!").classes("text-2xl")
|
||||
|
||||
|
||||
|
||||
ui.run(storage_secret="THIS_NEEDS_TO_BE_CHANGED", dark=True) #TODO: storage_secret?
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user