main.py 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. #!/usr/bin/env python3
  2. '''This is only a very simple authentication example which stores session IDs in memory and does not do any password hashing.
  3. Please see the `OAuth2 example at FastAPI <https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/>`_ or
  4. use the great `Authlib package <https://docs.authlib.org/en/v0.13/client/starlette.html#using-fastapi>`_ to implement a real authentication system.
  5. Here we just demonstrate the NiceGUI integration.
  6. '''
  7. import os
  8. import uuid
  9. from typing import Dict
  10. from fastapi import Request
  11. from fastapi.responses import RedirectResponse
  12. from starlette.middleware.sessions import SessionMiddleware
  13. from nicegui import app, ui
  14. # put your your own secret key in an environment variable MY_SECRET_KEY
  15. app.add_middleware(SessionMiddleware, secret_key=os.environ.get('MY_SECRET_KEY', ''))
  16. # in reality users and session_info would be persistent (e.g. database, file, ...) and passwords obviously hashed
  17. users = [('user1', 'pass1'), ('user2', 'pass2')]
  18. session_info: Dict[str, Dict] = {}
  19. def is_authenticated(request: Request) -> bool:
  20. return session_info.get(request.session.get('id'), {}).get('authenticated', False)
  21. @ui.page('/')
  22. def main_page(request: Request) -> None:
  23. if not is_authenticated(request):
  24. return RedirectResponse('/login')
  25. session = session_info[request.session['id']]
  26. with ui.column().classes('absolute-center items-center'):
  27. ui.label(f'Hello {session["username"]}!').classes('text-2xl')
  28. # NOTE we navigate to a new page here to be able to modify the session cookie (it is only editable while a request is en-route)
  29. # see https://github.com/zauberzeug/nicegui/issues/527 for more details
  30. ui.button('', on_click=lambda: ui.open('/logout')).props('outline round icon=logout')
  31. @ui.page('/login')
  32. def login(request: Request) -> None:
  33. def try_login() -> None: # local function to avoid passing username and password as arguments
  34. if (username.value, password.value) in users:
  35. session_info[request.session['id']] = {'username': username.value, 'authenticated': True}
  36. ui.open('/')
  37. else:
  38. ui.notify('Wrong username or password', color='negative')
  39. if is_authenticated(request):
  40. return RedirectResponse('/')
  41. request.session['id'] = str(uuid.uuid4()) # NOTE this stores a new session ID in the cookie of the client
  42. with ui.card().classes('absolute-center'):
  43. username = ui.input('Username').on('keydown.enter', try_login)
  44. password = ui.input('Password').props('type=password').on('keydown.enter', try_login)
  45. ui.button('Log in', on_click=try_login)
  46. @ui.page('/logout')
  47. def logout(request: Request) -> None:
  48. if is_authenticated(request):
  49. session_info.pop(request.session['id'])
  50. request.session['id'] = None
  51. return RedirectResponse('/login')
  52. return RedirectResponse('/')
  53. ui.run()