112
Views
7
Comments
Efficient and Secure Role-Based UI Visibility Management in Reactive Applications

Hello!

I'm currently developing a reactive application and managing user permissions based on roles. I’ve created 8 roles and need to configure what users can see. Setting access to screens is straightforward with the roles section, but I’m facing challenges when it comes to hiding/showing parts of the UI based on roles.

Currently, I use a data action at the start of each screen to output boolean variables such as IsITAdmin to define roles. However, this approach requires repeating the same data action on each screen and block, which doesn’t seem efficient.

I was thinking of creating a server action and calling it on every screen, but I am not sure in which event I should call it (initialize, ready, or render).

I have looked around the forum and I can see different approaches (e.g., using JavaScript to check a role), but I am wondering what is the most common approach.


My questions are:

  1. Is using a data action for each screen and block the right approach to manage UI visibility based on roles?
  2. How can I optimize this process to avoid redundancy and improve efficiency?
  3. What is the best way to securely manage role-based UI visibility?
  4. If I create a server action for role checking, in which event (initialize, ready, render) should I call it?


Has anyone implemented a similar setup, or does anyone have advice on best practices for this scenario?


Thank you,

Andrea

2024-09-17 08-54-53
Jerome Rajadurai J

Hi @Andrea Caselli ,

Its a really awesome bunch of questions.

There are many ways to resolve the scenario but speaking of Optimized solution i can suggest the below idea.  Try to implement both the points to improve performance.

1. Use DataAction to retrieve server data, So that you can display a loader or temporary widget till the time its loaded fully (By Using DataAction.IsDataFetched property). This answers point 3 that UI data is loaded only after the role confirmation is obtained from server.

2. Inside DataAction use a server action to retrieve data and increase the Server action cache time so that the data is retrieved fast on the second block/action hit.

This method allows to ensure a server check is made and its executed on loading of the page/block.

UserImage.jpg
Andrea Caselli

Hi @Jerome Rajadurai J 

Thank you for your reply! That's definitely a more refined approach than mine and if I will decide in the end to continue using the Data Action approach I will definitely refine it by using your suggestions. Thanks!

2021-10-09 07-57-44
Stefan Weber
 
MVP

Hi Andrea,

Assuming that your roles - or role assignments to be more specific - are not constantly changing one way to is to modify the existing UserInfo block (if using the default application templates). The default UserInfo block is part of the individual default layouts. In its standard configuration it calls a GetUserName client action in the OnInitialize handler of the block which in turn refreshes the GetUserNameFromServer data action.

You can hook into that data action and retrieve additional information like the assigned roles. Since you need the roles for UI visibility you would return a boolean value for each individual role. like AppIsManager, AppIsAdmin, AppIsOperator asf.

The default UserInfo block sets a client variable username to the retrieved username from the server. You would have to create additional client variables for your roles.

But take note that - at least from my perspective - the default UserInfo block has a design flaw. Storing the result of the username takes place in the same client action (GetUsername) where the data action is refreshed. Data refreshing is an asynchronous task, so it is not ensured that the data is already retrieved when assigning the result to the client variables.

A better option is to add an OnAfterFetch action to the GetUserNameFromServer data action and make all client variable assignments there.

In your UI you would use the Client variables to enable certain elements, but you have to make sure to do a proper role checking in your server/service actions as well.

Best

Stefan



UserImage.jpg
Andrea Caselli

Hi @Stefan Weber 

This is another interesting approach that I didn't consider. I need to decide if I want to potentially expose my UI to users who are capable of manipulating client variables. I definitely need to do, as you said, a proper role checking in server actions.

Thank you for your reply!

Andrea

2021-10-09 07-57-44
Stefan Weber
 
MVP

Yes. That is exactly the point to consider. But everything on the client side can be changed. Either in local storage or by directly modifying the javascript code or its result. That is why UI manipulation is not a security measurement.

2021-11-12 04-59-31
Manikandan Sambasivam

@Andrea Caselli 

  1. Is using a data action for each screen and block the right approach to manage UI visibility based on roles?

    • Using a data action on each screen and block is one way to manage role-based UI visibility, but it can lead to redundancy and maintenance challenges. A more efficient approach involves centralizing role-checking logic.
  2. How can I optimize this process to avoid redundancy and improve efficiency?

    • Centralize the role-checking logic in a server action and call it once per user session. Store the role information in session variables or client-side variables to avoid repetitive server calls.
  3. What is the best way to securely manage role-based UI visibility?

    • Use server-side logic to determine roles and permissions, and then pass this information to the client side securely. Ensure sensitive information is not exposed to unauthorized users.
  4. If I create a server action for role checking, in which event (initialize, ready, render) should I call it?

    • Call the server action during the OnInitialize event of a layout block or a master screen that loads once per user session. This ensures roles are checked early and the information is available throughout the application.

Recommended Approach

  1. Create a Server Action for Role Checking:

    • Create a server action (e.g., CheckUserRoles) that retrieves the roles of the logged-in user.
    • This action should output boolean variables for each role (e.g., IsITAdmin, IsManager).
  2. Call the Server Action on Session Start:

    • In your main layout block or a master screen, use the OnInitialize event to call the CheckUserRoles server action.
    • Store the results in session variables or client-side variables.
  3. Use Session Variables or Client Variables:

    • Store the role information in session variables (e.g., Session.IsITAdmin) or in client-side variables using OutSystems' client-side storage mechanisms.
  4. Bind UI Elements to Role Variables:

    • Bind UI elements' visibility properties to these variables. For example, set the Visible property of a container to Session.IsITAdmin.
UserImage.jpg
Christine


Hi, Stefan

I was looking for a safe and high-performance solution to control UI visibility role-based and came across your solution here.

I implemented it this way (especially with the assignment after the OnAfterFetch event) and it works great.

In addition, I created a client action as a function that does nothing but evaluate the client variables and then return the Boolean result (simple if with assignment). I can now use this function for each screen and screen element (for example containers) to control the visibility. 

This also creates the advantage that when the roles are changed or new additional roles are added, this can be converted centrally in the global client action.

And in addition the client variables can also be used for defining classes on elements (for to make them invisible for example) :

                                    If( Client.Has_readOnly = True,"display-none","")

Thus, one control per screen is omitted and the end user authorizations can be queried stably by the client variables over the duration of the session.

Great solution!! Thank you for that!

Christine

Community GuidelinesBe kind and respectful, give credit to the original source of content, and search for duplicates before posting.