Flask JWT Roles for User / Admin Student Lesson
Flask JWT Roles for User / Admin User student lesson presented by Team WRONG (Will, Rayyan, Jason, Nathan, and Grayson)
Flask JWT Roles for User / Admin User
Presented by Team WRONG
How To Authenticate Flask API Using JWT
https://www.loginradius.com/blog/engineering/guest-post/securing-flask-api-with-jwt/ https://github.com/nighthawkcoders/flask_portfolio/issues/42
Rayyan Darugar & Nathan Obodovski
Role-Based Authorization and Routes for Authorization
The decorators and “@roles_required()”
Decorators are essentially special functions that modify another function, placed before the function to be modified using the format “@name()”
- You can actually define the function by defining a regular function with the same “name” as in the “@name()”, or import it which is what we will do We can use this decorator “@roles_required()” to decorate a function, making it so the function runs ONLY if the decorator is fulfilled
- Decorator is fulfilled if the user is 1. logged in, and 2. has the role names specified in the decorator
- If these conditions are not fulfilled, the “Unauthorized access” error will be shown and user is redirected to USER_UNAUTHORIZED_ENDPOINT (check chatgpt for how to edit, maybe include that too)
from flask import route # import route function to use as decorator
from flask_user import roles_required # import roles_required function to use as decorator
# HEY!!! note that flask_user import has been yoinked, so this import no longer exists
# there do exist other flask alternatives, but they functionally do the same thing just with different lines of code
# the goal is to teach you the concepts of how we can define routes, decorate functions, check for roles, define endpoints, etc.
# if we get word of an alternative to specifically use, it'll be explained here too
# General example
@route('Path') # replace "Path" with the actual path to the page the person is accessing
@roles_required('Role') # replace "Role" with the roles the person needs to have
def function(): # replace function and pass with the actual function and code
pass
# Specific example
@route('/admin/dashboard')
@roles_required('Admin')
def admin_dashboard():
pass
Examining the Example Code
“@route(‘Path’)”
- Essentially every function that you want to use to display something at another page needs to have this @route decorator as the outer-most decorator
- Routes are basically the URL of the page you want to add the function to
- In the example, I want to add some functionality to the page with the URL /admin/dashboard (which is after the base URL)
- Note that a “’/’” route just means home
“@roles_required(‘Role’)”
- Again, this ensures that user is 1. logged in and 2. has the proper roles to access the route specified in “@route(‘Path’)”
- In the example, the decorator checks that the user has the ‘Admin’ role first before accessing the page /admin/dashboard and running the function to create the page
- Note that this is case sensitive, so the role the user must have is ‘Admin’ and not ‘admin’
Adding Complexity to Roles with AND/OR
We now can check a user’s role before accessing a route, very cool, but we can make it more complex and check for multiple roles or if they have at least 1 out of mulltiple roles using AND and OR respectively
- To use AND: separate the different role names with commas in the decorator
- To use OR: specify the role names in a list, using [], within the decorator See below for examples
# Same example as above, but incorporating the AND, OR, and both AND/OR checks
# AND
@route('/admin/dashboard')
@roles_required('Admin', 'Premium') # Checks that user has both 'Admin' AND 'Premium' role before allowing access to route
def admin_dashboard():
pass
# OR
@route('/admin/dashboard')
@roles_required(['Admin', 'Premium']) # Checks that user has either 'Admin' OR 'Premium' role before allowing access to route
def admin_dashboard():
pass
# Both AND/OR
@route('/admin/dashboard')
@roles_required('Admin', ['Premium', 'VIP']) # Checks that user has both 'Admin' AND either 'Premium' OR 'VIP' role before allowing access to route
def admin_dashboard():
pass
Changing Data-Models to Add Roles
https://flask-user.readthedocs.io/en/latest/data_models.html#roleanduserroledatamodels probably split this among one-two people
Grayson Guyot and Will Bartelt
Data models
Data models define a structure of data as well as the relationship between different parts and elements of the data. You can name your single data model class User. This name can be anything you want. The name can be fixed or flexible depending on the requirments of what is being applied to.
Flexible data model property names are dynamic and are best for when your data structures change over time. This means it is easier to adapt and change. It gives it less security and might require more effort for validation. Examples: UserRoles.id, UserRoles.user_id, UserRoles.role_id
Fixed data model property names are often explicitly defined and remain constant. They are normally consistent and stable which is well suited for when you have a clear data requirment. They are less adaptable to changes in data requirments. Examples: User.id, User.username, User.password, User.email
Roles and User Roles: When you add a roles and user roles data models to your function, you add a form of role based authentification which means the original user function must also define a roles relationship property. This makes your data models more manegable by giving it a system that is organized by its roles.