Implementing Roles and Permissions for Custom Entities in Liferay: Our Approach

26.04.25 09:14 PM - By Prakash

At ReactorBee, we recently worked on a client project where we needed to implement Roles and Permissions for custom entities built on Liferay 7.4.
Instead of building a custom permission system, we smartly leveraged Liferay's Out-of-the-Box (OOTB) Roles and Permissions framework — but with a few important extensions.

Here’s a step-by-step walkthrough of how we achieved it.

Why We Needed This
  • The client had multiple custom modules (entities) inside Liferay.
  • They needed granular control over what different roles could do with each entity.
  • Permissions needed to be manageable from Liferay's Control Panel without custom UIs.
Step-by-Step Implementation

Step 1: Add a default.xml in the Service Module

                In the Service Module of each custom entity, we created a default.xml file under the resource-actions folder.

This file defined Model Resource Permissions for each entity and listed the actions supported.


Sample (service/src/main/resources/resource-actions/default.xml):

<?xml version="1.0"?>
<!DOCTYPE resource-action-mapping PUBLIC "-//Liferay//DTD Resource Action Mapping 7.4.0//EN" "http://www.liferay.com/dtd/liferay-resource-action-mapping_7_4_0.dtd">

<resource-action-mapping>
    <model-resource>
        <model-name>com.example.model.EntityName</model-name>
        <portlet-ref>
            <portlet-name>com_example_web_EntityPortlet</portlet-name>
        </portlet-ref>
        <root>true</root>
        <weight>1</weight>
        <permissions>
            <supports>
                <action-key>VIEW</action-key>
                <action-key>EDIT</action-key>
                <action-key>DELETE</action-key>
                <action-key>CUSTOM_ACTION</action-key>
            </supports>
            <site-member-defaults />
            <guest-defaults />
            <guest-unsupported />
        </permissions>
    </model-resource>
</resource-action-mapping>


  • action-key placeholders represent the actions you want to define for your entity. 
  • model-name is your entity's fully qualified class name.
  • Step 2: Add a default.xml in the Web Module

                    In the Web Module (Portlet Module) associated with the entity, we also created a⁣ default.xml

    This file defined Portlet Resource Permissions.


    Sample (web/src/main/resources/resource-actions/default.xml):

    <?xml version="1.0"?>
    <!DOCTYPE resource-action-mapping PUBLIC "-//Liferay//DTD Resource Action Mapping 7.4.0//EN" "http://www.liferay.com/dtd/liferay-resource-action-mapping_7_4_0.dtd">

    <resource-action-mapping>
        <portlet-resource>
            <portlet-name>com_example_web_EntityPortlet</portlet-name>
            <permissions>
                <supports />
                <site-member-defaults />
                <guest-defaults />
                <guest-unsupported />
            </permissions>
        </portlet-resource>
    </resource-action-mapping>

    • This ensures the portlet itself is recognized in the Roles UI and can be assigned permissions.

    Step 3: Create/Update portlet.properties

    In the Web Module and Service Module, we created a portlet.properties file (if not already existing) and added the following line:

    resource.actions.configs=resource-actions/default.xml

    • This tells Liferay to load the default.xml we created, so action keys are properly registered when the module deploys.

    Step 4: Add Action Key Labels

    We updated the module’s Language.properties to define readable labels for each action key.

    Example:

    model.resource.com.example.model.EntityName=Entity
    action.VIEW=View
    action.EDIT=Edit
    action.DELETE=Delete
    action.CUSTOM_ACTION=Custom Action

    • These appear in the Liferay Control Panel under Roles → Define Permissions.

    Step 5: Handle Liferay’s 64 Action Keys Limit

        -    In Liferay, one entity can only have up to 64 action keys because of internal storage as bit fields.

        -    To manage hundreds of permissions across many entities:

                    -    We designed modular entities with focused sets of action keys.

                    -    Split large functionality into smaller logical modules when needed.

    Result: No entity exceeded 64 keys, ensuring stability and smooth upgrades later.

    Step 6: Provide a Headless API for Frontend

    To simplify frontend integration:

    • We exposed a custom Headless API that returns all action keys available to the logged-in user, grouped by entity.

    • The frontend team only needed one API call to fetch all permissions at once.

    ✅ This minimized complexity and accelerated frontend development.

    Additional Note

    • Custom Action Keys for Liferay Objects:
      We also implemented custom action keys for Liferay Objects (dynamic entities).
      we’ll explain it separately in the next blog post.


    Conclusion

    By correctly setting up resource actions in both Service and Web modules, and by aligning closely with Liferay’s framework:

    • We delivered a scalable, admin-manageable, and future-proof permissions system.

    • No heavy custom development was needed beyond smart configuration.

    At ReactorBee, we always aim to maximize platform capabilities to deliver elegant, enterprise-ready solutions quickly and reliably.

    Prakash

    ReactorBee Private Ltd
    http://www.reactorbee.com/