In modern web applications, security is paramount, especially when dealing with sensitive user data or performing critical operations. Role-based Access Control (RBAC) is a popular approach to manage access permissions effectively. Combining RBAC with JSON Web Token (JWT) authentication can provide a robust security mechanism for FastAPI applications. In this blog post, we'll delve into a Python code snippet that implements RBAC with JWT authentication in a FastAPI application.
def requires(category, roles):
def decorator(func):
@wraps(func)
async def wrapper(request: Request, *args, **kwargs):
authorizationToken = request.headers.get("authorization", "")
# FOR hasini add a decrypt logic
scheme, credentials = (
authorizationToken.split(" ", 1)
if " " in authorizationToken
else ("", "")
)
if not scheme == "Bearer":
raise HTTPException(
status_code=403, detail="Invalid authentication scheme."
)
decoded_token = decode_token(credentials)
if not decoded_token:
raise HTTPException(status_code=401, detail="Invalid token")
glbId = decoded_token["UserId"] + "_" + decoded_token["infoId"]
userInfoObj = glblobj.user.get(glbId, {})
tokenValid = userInfoObj.get("tokenActive", False)
try:
payload = await request.json()
except json.decoder.JSONDecodeError as e:
payload = {}
type_value = payload.get("type") if category == "$type" else category
permissions = userInfoObj.get("Permissions", {}).get(type_value, {})
if not any(permissions[permission_order.index(role)] == 1 for role in roles):
raise HTTPException(status_code=403, detail="Insufficient privileges")
if "activeUser" in func.__code__.co_varnames:
user = {} # Replace this with the actual user information
user.update(userInfoObj)
user.update(decoded_token)
kwargs["activeUser"] = user
if "authorizationToken" in func.__code__.co_varnames:
kwargs["authorizationToken"] = authorizationToken
return await func(request, *args, **kwargs)
return wrapper
return decorator
Understanding the Code
Let's break down the provided Python code:
- Imports: The code imports necessary modules and libraries such as
functools
,json
,FastAPI
,Request
,Depends
,HTTPException
,HTTPBearer
,jwt
,config
fromdecouple
, and custom utility and global class modules. - Constants Initialization: It initializes constants such as
JWT_SECRET
,JWT_ALGORITHM
,ACCESS_TOKEN_EXPIRES_IN
, andREFRESH_TOKEN_EXPIRES_IN
using environment variables. - requires Decorator: This decorator function facilitates role-based authorization. It takes two parameters:
category
(which can be either a string or "$type") androles
(a list of roles). It wraps the API endpoint functions to enforce role-based authorization. - decode_token Function: This function decodes the JWT token. It verifies the token's authenticity using the provided secret and algorithm. If the token is valid and not expired, it returns the decoded token; otherwise, it returns None.
- Wrapper Function: This function is generated by the
requires
decorator. It intercepts the incoming requests, checks the authorization token, decodes it, verifies the user's permissions against the specified roles, and then calls the wrapped function if authorization is successful.
Usage Example
@router.get("/", tags=["Company Profile"])
@requires("accounts", ["update"])
async def getCompanyDetails(request: Request):
return await CompanyModule.get()
In this example, the getCompanyDetails
function is decorated with @requires("accounts", ["update"])
, indicating that only users with the "update" role in the "accounts" category can access this endpoint. When a request is made to this endpoint, the requires
decorator intercepts it, verifies the user's permissions, and only allows access if the user meets the specified criteria.
Conclusion
Implementing role-based access control with JWT authentication adds an extra layer of security to FastAPI applications, ensuring that only authorized users can access certain endpoints or perform specific actions. By understanding the provided code snippet and its usage, developers can effectively integrate RBAC into their FastAPI projects, safeguarding sensitive data and maintaining the integrity of their applications.