Figure 8-13.
Approaches for implementing complex RBAC models
You can implement complex RBAC authorization logic using
abstract dependencies, as shown in Example 8-20.
Example 8-20. Implementing complex RBAC authorization
using abstract dependencies
# dependencies/[Link]
from typing import Annotated
from entities import User
from fastapi import APIRouter, Depends, HTTPExcep
from [Link] import AuthService
CurrentUserDep = Annotated[User, Depends(AuthServ
async def has_role(user: CurrentUserDep, roles: l
if [Link] not in roles:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN
detail="Not allowed to perform this a
)
return user
# routes/[Link]
...
@[Link](
"/image",
dependencies=[Depends(lambda user: has_role(u
)
async def generate_image_controller():
...
@[Link](
"/text", dependencies=[Depends(lambda user: h
)
async def generate_text_controller():
...
In summary, RBAC simplifies permission management by
assigning permissions to roles rather than individuals, making
it easier to manage and audit. It is scalable and efficient for
organizations with well-defined roles and responsibilities.
However, RBAC can lead to role explosion when many granular
roles are necessary, making it hard to manage. It also lacks the
flexibility to handle complex hierarchical relationships like
teams and groups alongside setting dynamic permissions based
on attributes like user preferences, time, and privacy settings,
which limits its granularity compared to ReBAC or ABAC.
Relationship-Based Access Control
Relationship-based access control is an extension of RBAC with a
focus on relationships between resources and users.
With this mode, instead of just setting roles at the user level
across the entire application, you must set roles and
permissions at the resource level. This means you will have to
confirm the actions each role can take on every resource type.
For example, instead of assigning a “moderator” role to a user
that grants access to all resources (i.e., conversations, teams,
users, etc.), you would assign specific permissions to the
moderator role for each resource. A moderator might have read
and delete permissions on the conversation resource but only
read permission on the team resource.
This model allows you to create authorization policies based on
hierarchical and nested structures within your data and be
visualized as graphs where nodes can be represented as
resources/identities and edges as relationships.
Since you can create authorization rules based on relationships,
this can save you lots of time setting permissions at an instance
level. As an example, instead of sharing every private LLM
conversation in your app one by one, you can group them
under a team or a folder and share the folder or add members
to the team instead. In ReBAC, children instances can inherit
parent’s permissions, as shown in Figure 8-14. It’s the same for
related instances if needed.
Figure 8-14. Example ReBAC where a user can see the team’s private conversations
and threads
The example shown in Figure 8-14 demonstrates both
organization and hierarchical relationships between users (i.e.,
teams and members) and resources (conversations and
threads).
TIP
If you decide to adopt the ReBAC model, I recommend visually mapping out the
relationships between resources and identities in your application.
This work includes mapping out policies (i.e., rules), resources and available actions
on them, resource-level roles, and relationships between entities.
A big problem that ReBAC solves by extending RBAC is the
explosion of roles within the RBAC model by combining
relationships with roles. It is ideal for managing permissions in
complex hierarchical structures and allows for reverse queries,
enabling efficient permission definitions using teams and
groups. However, ReBAC can be complex to implement and
maintain, resource-intensive, difficult to audit, and not as fine-
grained as ABAC for dynamic permissions based on attributes
like time or location.
Attribute-Based Access Control
Attribute-based access control authorization model expands
basic RBAC roles by setting access control rules based on
conditions applied to attributes to implement more granular
policies. As an example, ABAC can prevent users from
uploading sensitive documents into your RAG-enabled services
if the document contains personally identifiable information
(PII) (i.e., upload.has_pii=true ).
Another example of ABAC can be seen in SaaS applications like
ChatGPT where only paid users have access to the service’s
premium GenAI models (see Figure 8-15).
Figure 8-15. ABAC example where only paid users have access to premium GenAI
models
Since the freedom to set policies based on attributes is infinite,
the ABAC model allows for significantly fine-grained
authorization policies. However, ABAC can be cumbersome for
managing hierarchical structures, making it challenging to
determine which users have access to a specific resource. For
example, if you have a policy that grants access based on
attributes like user role, data sensitivity level, and project
membership, determining all users who can access a specific
dataset requires evaluating these attributes for every user.
While less complicated than ReBAC, ABAC can still be
challenging to implement, in particular in large and complex
applications that support a large number of roles, users, and
attributes.
Hybrid Authorization Models
If you’ve worked with larger applications in the past, you will
notice that they combine features of the RBAC, ReBAC, and
ABAC authorization models. For instance, administrators may
have access to any resource and user
management/authentication features (RBAC), and users can
share their private resources by setting visibility attribute to
public (ABAC) and can add members to their team for
collaborating on private resources.
A hybrid approach combining RBAC, ReBAC, and ABAC models
may give you the strengths of all the authorization models:
RBAC simplifies permission management by assigning roles
to users, making it easy to manage and audit.
ReBAC is perfect for managing hierarchical relationships and
reverse queries, making it suitable for complex hierarchical
structures.
ABAC provides fine-grained control based on user and
resource attributes, allowing for dynamic and context-aware
permissions.
Figure 8-16 demonstrates the hybrid authorization model.
Figure 8-16. Hybrid authorization model based on roles, relationships, and attributes
To implement the hybrid authorization combining RBAC,
ReBAC, and ABAC models, you can follow Example 8-21.
Example 8-21. Implementing the hybrid authorization
model combining RBAC, ReBAC, and ABAC
# dependencies/[Link]
from typing import Annotated
from fastapi import Depends, HTTPException, statu
... # import services and entities here
CurrentUserDep = Annotated[User, Depends(AuthServ
TeamMembershipRep = Annotated[Team, Depends(TeamS
ResourceDep = Annotated[Resource, Depends(Resourc
def authorize(
user: CurrentUserDep, resource: ResourceDep,
) -> bool:
if [Link] == "ADMIN":
return True
if [Link] in [Link]:
return True
if resource.is_public:
return True
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN, de
)
# routes/[Link]
from [Link] import authorize
from fastapi import APIRouter, Depends
router = APIRouter(
dependencies=[Depends(authorize)], prefix="/g
)
@[Link]("/image")
async def generate_image_controller(): ...