-
Notifications
You must be signed in to change notification settings - Fork 0
Authentication
Handles user registration, authentication, and role management.
- The database must be configured and working.
- The
.streamlit/secrets.tomlfile must be configured with all the necessary data and credentials to access the database and the cookie authentication details.
This project uses Streamlit-Authenticator to manage authentication, that provides an Authenticator object.
The Authenticator provides pre-made functionalities:
- Manages Login and Logout.
- Provides a Login and Logout form frontend component.
- Manages the authentication cookies for an automatic login.
- Manages the current logged-in user's info.
It is stored in the Streamlit Session State at run-time, so it is sent to every browser session.
It also contains all the users credentials in a specific format (using the backend.models.user.to_credentials_dict() function), including the one that is currently logged in.
To properly integrate it into the system, there are auxiliary functions to create and retrieve this object.
This is a summary of the get_or_create_authenticator_object() function in backend/authentication/authenticator_creation.py.
flowchart TD
%% Grouping related processes
subgraph Database_Operations ["Database Operations"]
GetDbConnection@{shape: cyl, label: "Get DB Connection"}
FetchUsers@{label: "Fetch Users"}
OrganizeCredentials@{shape: stadium, label: "Organize Credentials"}
end
style Database_Operations fill:#5f3c2599
subgraph Session_State_Operations ["Session State Operations"]
SetAuthenticator["Set Authenticator"]
GetAuthenticator["Get Authenticator"]
end
style Session_State_Operations fill:#2a5d3399
Start@{shape: circ, label: "Start"}
Stop@{shape: dbl-circ, label: "Stop"}
AuthenticatorExistsCheck{Authenticator Exists?}
ReturnAuthenticator@{shape: stadium, label: "Return Authenticator"}
GetAuthenticationCookie@{label: "Get Authentication Cookie"}
InstantiateAuthenticator@{shape: stadium, label: "Instantiate Authenticator"}
Start --> GetAuthenticator
GetAuthenticator --> AuthenticatorExistsCheck
AuthenticatorExistsCheck -- "No, create the Authenticator Object" --> GetDbConnection
GetDbConnection --> FetchUsers
FetchUsers --> OrganizeCredentials
OrganizeCredentials --> GetAuthenticationCookie
GetAuthenticationCookie --> InstantiateAuthenticator
InstantiateAuthenticator --> SetAuthenticator
SetAuthenticator --> ReturnAuthenticator
AuthenticatorExistsCheck -- "Yes" --> ReturnAuthenticator
ReturnAuthenticator --> Stop
This mechanism updates the user's current data within the authenticator object whenever it is modified in the database (e.g., email or name change), to avoid data discrepancies during the current session.
Note
A simple refresh of the page would solve the problem (as it resets the session state), but updating in real time improves the user experience, avoiding disruptions in the flow of use.
These functions are in backend/authentication/authenticator_manipulation.py.
-
The
add_new_user_to_authenticator_object()function does two jobs:- Adds a new user to the current session's authenticator object.
- Edits an existing user in the current session's authenticator object.
-
The removal process is done in the
remove_user_in_authenticator_object()function.
This is a summary of all three functions combined.
flowchart TD
%% Subgraph: Session State Operations
subgraph Session_State_Operations ["Session State Operations"]
UpdateAuthenticator@{label: "Set Authenticator"}
end
style Session_State_Operations fill:#2a5d3399
Start@{shape: circ, label: "Start"}
Stop@{shape: dbl-circ, label: "Stop"}
GetOrCreateAuthenticatorObject@{shape: subproc, label: "Get Or Create Authenticator Object"}
CheckOperation{Operation}
RemoveOldUser@{label: "Remove Old User"}
EditRemoveOldUser@{label: "Remove Old User"}
AddNewUser@{label: "Add New User"}
Fork@{shape: fork}
Join@{shape: fork}
Merge@{shape: diamond, label: " "}
Start --> GetOrCreateAuthenticatorObject
GetOrCreateAuthenticatorObject --> CheckOperation
CheckOperation --> Fork
Fork -- "Add New User" --> AddNewUser
Fork -- "Edit User" --> EditRemoveOldUser
EditRemoveOldUser --> AddNewUser
Fork -- "Remove User" --> RemoveOldUser
AddNewUser --> Join
RemoveOldUser --> Join
Join --> Merge
Merge --> UpdateAuthenticator
UpdateAuthenticator --> Stop
These functions are in backend/authentication/current_user_data.py.
They gather data about the current user from the session state:
- Role
- Full Name (First/Last name)
- Username
- Login status (logged-in:
True, not logged-in:False)
Note
Streamlit-Authenticator puts the role in the session state with key "roles".
These functions are in backend/authentication/user_data_manipulation.py.
They act as an interface between the frontend and the Authenticator manipulation functions. Each one of these validates the input following the rules set in Streamlit-Authenticator's Validator class (e.g. string length, security requirements, etc).
These are the functions:
-
create_new_user: Creates a new user withadd_new_user_to_authenticator_object() -
edit_username: Edits a user's username withedit_user_in_authenticator_object() -
edit_email: Edits a user's email withedit_user_in_authenticator_object() -
edit_password: Edits a user's password withedit_user_in_authenticator_object() -
edit_first_last_name: Edits a user's first and/or last name withedit_user_in_authenticator_object() -
edit_role: Edits a user's role withedit_user_in_authenticator_object()
Important
Due to a technical limitation on how Streamlit-Authenticator works, after the user has edited its own username, they must be logged-out.
This is mostly due to the authentication cookie, and the fact that, for some reason, it cannot be edited. After logging back in, the cookie is updated with the new username.
This is a summary of all functions combined.
flowchart TD
%% Subgraph: Session State Operations
subgraph Database_Operations ["Database Operations"]
GetDbConnection@{shape: cyl, label: "Get DB Connection"}
UpdateDatabase@{label: "Update Database with the New Data"}
end
style Database_Operations fill:#5f3c2599
Start@{shape: circ, label: "Start"}
Stop@{shape: dbl-circ, label: "Stop"}
ValidateInput@{label: "Validate All Inputs"}
CheckValidation{Are all inputs valid?}
AuthenticatorManipulation@{shape: subproc, label: "Authenticator Manipulation"}
Error@{shape: odd, label: "Raise Exception"}
Start --> ValidateInput
ValidateInput --> CheckValidation
CheckValidation -- "Yes" --> GetDbConnection
GetDbConnection --> UpdateDatabase
UpdateDatabase --> AuthenticatorManipulation
AuthenticatorManipulation --> Stop
CheckValidation -- "No" --> Error
Error --> Stop
- Official Streamlit Documentation
- Other Modules: