@@ -288,6 +288,7 @@ Authentication
288288 * - Examples
289289 - | `basic_auth.py <https://github.com/miguelgrinberg/microdot/blob/main/examples/auth/basic_auth.py >`_
290290 | `token_auth.py <https://github.com/miguelgrinberg/microdot/blob/main/examples/auth/token_auth.py>`_
291+
291292The authentication extension provides helper classes for two commonly used
292293authentication patterns, described below.
293294
@@ -355,6 +356,91 @@ protect your routes::
355356 @auth
356357 async def index(request):
357358 return f'Hello, {request.g.current_user}!'
359+
360+ User Logins
361+ ~~~~~~~~~~~
362+
363+ .. list-table ::
364+ :align: left
365+
366+ * - Compatibility
367+ - | CPython & MicroPython
368+
369+ * - Required Microdot source files
370+ - | `login.py <https://github.com/miguelgrinberg/microdot/tree/main/src/microdot/auth.py >`_
371+ | `session.py <https://github.com/miguelgrinberg/microdot/tree/main/src/microdot/session.py>`_
372+ * - Required external dependencies
373+ - | CPython: `PyJWT <https://pyjwt.readthedocs.io/ >`_
374+ | MicroPython: `jwt.py <https://github.com/micropython/micropython-lib/blob/master/python-ecosys/pyjwt/jwt.py>`_,
375+ `hmac.py <https://github.com/micropython/micropython-lib/blob/master/python-stdlib/hmac/hmac.py>`_
376+ * - Examples
377+ - | `login.py <https://github.com/miguelgrinberg/microdot/blob/main/examples/login/login.py >`_
378+
379+ The login extension provides user login functionality. The logged in state of
380+ the user is stored in the user session cookie, and an optional "remember me"
381+ cookie can also be added to keep the user logged in across browser sessions.
382+
383+ To use this extension, create instances of the
384+ :class: `Session <microdot.session.Session> ` and :class: `Login <microdot.login.Login> `
385+ class::
386+
387+ Session(app, secret_key='top-secret!')
388+ login = Login()
389+
390+ The ``Login `` class accept an optional argument with the URL of the login page.
391+ The default for this URL is */login *.
392+
393+ The application must represent users as objects with an ``id `` attribute. A
394+ function decorated with ``@login.user_loader `` is used to load a user object::
395+
396+ @login.user_loader
397+ async def get_user(user_id):
398+ return database.get_user(user_id)
399+
400+ The application must implement the login form. At the point in which the user
401+ credentials have been received and verified, a call to the
402+ :func: `login_user() <microdot.login.Login.login_user> ` function must be made to
403+ record the user in the user session::
404+
405+ @app.route('/login', methods=['GET', 'POST'])
406+ async def login(request):
407+ # ...
408+ if user.check_password(password):
409+ return await login.login_user(request, user, remember=remember_me)
410+ return redirect('/login')
411+
412+ The optional ``remember `` argument is used to add a remember me cookie that
413+ will log the user in automatically in future sessions. A value of ``True `` will
414+ keep the log in active for 30 days. Alternatively, an integer number of days
415+ can be passed in this argument.
416+
417+ Any routes that require the user to be logged in must be decorated with
418+ :func: `@login <microdot.login.Login.__call__> `::
419+
420+ @app.route('/')
421+ @login
422+ async def index(request):
423+ # ...
424+
425+ Routes that are of a sensitive nature can be decorated with
426+ :func: `@login.fresh <microdot.login.Login.fresh> `
427+ instead. This decorator requires that the user has logged in during the current
428+ session, and will ask the user to logged in again if the session was
429+ authenticated through a remember me cookie::
430+
431+ @app.get('/fresh')
432+ @login.fresh
433+ async def fresh(request):
434+ # ...
435+
436+ To log out a user, the :func: `logout_user() <microdot.auth.Login.logout_user> `
437+ is used::
438+
439+ @app.post('/logout')
440+ @login
441+ async def logout(request):
442+ await login.logout_user(request)
443+ return redirect('/')
358444
359445Cross-Origin Resource Sharing (CORS)
360446~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0 commit comments