{"id":1822,"date":"2024-10-13T12:00:00","date_gmt":"2024-10-13T10:00:00","guid":{"rendered":"https:\/\/kindsonthegenius.com\/blog\/?p=1822"},"modified":"2026-08-28T10:02:44","modified_gmt":"2026-08-28T08:02:44","slug":"inventoryms-springboot-roles-and-privileges-2-the-data-model-and-api","status":"publish","type":"post","link":"https:\/\/kindsonthegenius.com\/blog\/inventoryms-springboot-roles-and-privileges-2-the-data-model-and-api\/","title":{"rendered":"InventoryMS \u2013 SpringBoot Roles and Privileges 2 ( The Data Model and API)"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><em>Learn how to implement SpringBoot roles and privileges with a fine-grained data model, REST API endpoints, user privilege assignments, and role-based access management.<\/em><\/p>\n\n\n<h2>TL;DR<\/h2>\n<ul>\n<li>\n<p><strong>SpringBoot roles and privileges<\/strong> can be implemented using either a basic role-based model or a more flexible fine-grained approach.<\/p>\n<\/li>\n<li>\n<p>The <strong>fine-grained approach<\/strong> lets users receive specific privileges from different roles instead of automatically inheriting every privilege from one role.<\/p>\n<\/li>\n<li>\n<p><strong>UserPrivilegeAssignment<\/strong> connects users with privileges while avoiding a direct many-to-many relationship.<\/p>\n<\/li>\n<li>\n<p>The implementation provides APIs to <strong>assign, retrieve, clear, and manage user privileges and roles<\/strong>.<\/p>\n<\/li>\n<li>\n<p>The <code>savePrivileges<\/code> operation <strong>clears existing privileges and assigns the new ones inside a transaction<\/strong> to keep the update consistent.<\/p>\n<\/li>\n<\/ul>\n<p>This is Part 3 SpringBoot Roles and Privileges implementation for our Inventory Management System (InventoryMS).<\/p>\n<p>In this tutorial, we would actually implement the Roles and Privileges in our Inventory Management System.<\/p>\n<p><strong>Content<\/strong><\/p>\n<ol>\n<li><a href=\"#t1\">The Basic\u00a0 Approach<\/a><\/li>\n<li><a href=\"#t2\">The Fine-Grained Approach<\/a><\/li>\n<li><a href=\"#t3\">The Roles Management Classes<\/a><\/li>\n<li><a href=\"#t4\">The Controller Endpoints<\/a><\/li>\n<li><a href=\"#t5\">How the savePrivileges Work<\/a><\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<p>Now, let\u2019s take some time to understand how management of roles and privileges work in Spring Boot. There are two approaches to handling Roles and Privileges in SpringBoot.<\/p>\n<ul>\n<li>The Basic Approach<\/li>\n<li>The Fine-grained Approach<\/li>\n<\/ul>\n<h4><strong id=\"t1\">1. The Basic Approach: User-&gt; Roles -&gt; Privilege Relationship<\/strong><\/h4>\n<p>The User -&gt; Role relationship could either be one-to-many or many-to-many.<\/p>\n<p>This means a User could have more that one role<\/p>\n<p>The Role -&gt; Privilege relationship could also either be one-to-many or many-to-many<\/p>\n<p>Generally, a Role would have multiple privileges<\/p>\n<p>Also, a user assigned a given role, would inherit all the privileges under that role ( we would not use this approach, we would use a more fine-grained approach)<\/p>\n<p><strong>To assign a User additional permissions, you could either:<\/strong><\/p>\n<ul>\n<li>assign the User additional Role that includes the desired permission<\/li>\n<li>add the desired permission to the Role the User currently holds<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h4><strong id=\"t2\">2. A Fine-Grained Approach: User -&gt; Privilege, Role -&gt; Privilege<\/strong><\/h4>\n<p>In this application, we would use the Fine-Grained Approach. The Basic Approach was used in <a href=\"https:\/\/youtu.be\/FzNqL3dxEwc?si=flIJrPzaIsS8fWcI\" target=\"_blank\" rel=\"noopener\">FleetMS version 2<\/a>.<\/p>\n<p>As mentioned above, if a user is assigned a role, he would automatically inherit all the privileges under that role. However, we would use this approach.<\/p>\n<p>In the fine-grained approach, a users could be assigned privileges\u00a0 from any role. This means that a user could be assigned some privileges from the ADMIN role and some privileges from the FINANCE MANAGER role.<\/p>\n<p>This also allows us to assign a user all the privileges under a given role if needed.<\/p>\n<p><strong>AssignAll and UnassignAll<\/strong><\/p>\n<p>Since a user has privileges and each privilege belongs to a role, we could implement \u2018Role Assignment\u2019 by assigning the user all the privileges belonging to specific role. Same for unassign as we. The screen appears as shown below:<\/p>\n<figure id=\"attachment_15098\" class=\"wp-caption alignnone\" style=\"width: 1024px;\" aria-describedby=\"caption-attachment-15098\"><a href=\"https:\/\/www.kindsonthegenius.com\/wp-content\/uploads\/2024\/10\/Screenshot-2024-10-13-at-10.09.17-scaled.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-15098 size-large\" src=\"https:\/\/www.kindsonthegenius.com\/wp-content\/uploads\/2024\/10\/Screenshot-2024-10-13-at-10.09.17-1024x640.jpg\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" srcset=\"https:\/\/www.kindsonthegenius.com\/wp-content\/uploads\/2024\/10\/Screenshot-2024-10-13-at-10.09.17-1024x640.jpg 1024w, https:\/\/www.kindsonthegenius.com\/wp-content\/uploads\/2024\/10\/Screenshot-2024-10-13-at-10.09.17-300x188.jpg 300w, https:\/\/www.kindsonthegenius.com\/wp-content\/uploads\/2024\/10\/Screenshot-2024-10-13-at-10.09.17-768x480.jpg 768w, https:\/\/www.kindsonthegenius.com\/wp-content\/uploads\/2024\/10\/Screenshot-2024-10-13-at-10.09.17-1536x960.jpg 1536w, https:\/\/www.kindsonthegenius.com\/wp-content\/uploads\/2024\/10\/Screenshot-2024-10-13-at-10.09.17-2048x1280.jpg 2048w, https:\/\/www.kindsonthegenius.com\/wp-content\/uploads\/2024\/10\/Screenshot-2024-10-13-at-10.09.17-600x375.jpg 600w\" alt=\"User Role\/Privilege assignment screen\" width=\"1024\" height=\"640\" \/><\/a>\n<figcaption id=\"caption-attachment-15098\" class=\"wp-caption-text\">User Role\/Privilege assignment screen<\/figcaption>\n<\/figure>\n<p>&nbsp;<\/p>\n<h4><strong id=\"t3\">3. Implementing the Roles Management Classes<\/strong><\/h4>\n<p>The following classes would participate in the Roles Management implementation:<\/p>\n<ul>\n<li><strong>User<\/strong> \u2013 create a OneToMany relationship between User and Privilege<\/li>\n<li><strong>Role<\/strong> \u2013 create a OneToMany relationship between Role and Privilege<\/li>\n<li><strong>Privilege<\/strong> \u2013 create a ManyToOner relation from Privilege to Role<\/li>\n<li><strong>UserPrivilegeAssignment<\/strong>\u00a0 \u2013 relates both User and Role (we use this so that we don\u2019t have to do a ManyToMany as this is a bit tricky to manage ????)<\/li>\n<\/ul>\n<p>We have chosen these models in such a way to avoid a many-to-many relationship since this is a bit tricky while working with Roles and Privileges in SpringBoot.<\/p>\n<p>&nbsp;<\/p>\n<h4><strong id=\"t4\">4. Implementing the Controller Endpoints<\/strong><\/h4>\n<p>We would need the following controller endpoints in addition to the 5 standard methods (getAll, getOne, add, edit, delete):<\/p>\n<table>\n<tbody>\n<tr>\n<td width=\"186\"><strong>Description<\/strong><\/td>\n<td width=\"137\"><strong>Route<\/strong><\/td>\n<td width=\"157\"><strong>Implemented In Controller<\/strong><\/td>\n<\/tr>\n<tr>\n<td width=\"186\">1. Save privileges<\/td>\n<td width=\"137\">POST: \/user\/{id}\/privileges<\/td>\n<td width=\"157\">UserPrivilegeAssignment<\/td>\n<\/tr>\n<tr>\n<td width=\"186\">2. Get User Privileges<\/td>\n<td width=\"137\">GET: \/user\/{id}\/privileges<\/td>\n<td width=\"157\">UserPrivilegeAssignment<\/td>\n<\/tr>\n<tr>\n<td width=\"186\">3. Get Users in Privilege<\/td>\n<td width=\"137\">GET: \/privilege\/{id}\/users<\/td>\n<td width=\"157\">UserPrivilegeAssignment<\/td>\n<\/tr>\n<tr>\n<td width=\"186\">4. Clear assigned privileges<\/td>\n<td width=\"137\">PUT:\/user\/{id}\/privileges\/clear<\/td>\n<td width=\"157\">UserPrivilegeAssignment<\/td>\n<\/tr>\n<tr>\n<td width=\"186\">5. Assign Role (assign all privileges in role)<\/td>\n<td width=\"137\">PUT:\/role\/{roleid}\/assign\/user\/{userid}<\/td>\n<td width=\"157\">Role<\/td>\n<\/tr>\n<tr>\n<td width=\"186\">6. UnAssign Role (unassign all privileges in role)<\/td>\n<td width=\"137\">DELETE:\/role\/{roleid}\/unassign\/user\/{userid}<\/td>\n<td width=\"157\">Role<\/td>\n<\/tr>\n<tr>\n<td width=\"186\">7. Get Privileges in Role<\/td>\n<td width=\"137\">GET:\/role\/{roleid}\/privileges<\/td>\n<td width=\"157\">Role<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<h4><strong id=\"t5\">5. How savePrivileges Work<\/strong><\/h4>\n<p>This controller method takes a list of Privileges retrieved from the request body as well as the user id retrieved from the path variable.<\/p>\n<p>It updates the user privileges by performing two steps:<\/p>\n<ul>\n<li>Step 1- clear existing user privileges<\/li>\n<li>Step 2 \u2013 assign the new privileges provided<\/li>\n<\/ul>\n<p>Note that this two steps has to be performed within a transaction. The function is given below:<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #888888;\">\/\/1. Save privileges<\/span>\n<span style=\"color: #555555; font-weight: bold;\">@Transactional<\/span>\n<span style=\"color: #555555; font-weight: bold;\">@PostMapping<\/span><span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"\/user\/{userid}\/privileges\"<\/span><span style=\"color: #333333;\">)<\/span>\n<span style=\"color: #008800; font-weight: bold;\">public<\/span> ResponseEntity<span style=\"color: #333333;\">&lt;<\/span>String<span style=\"color: #333333;\">&gt;<\/span> <span style=\"color: #0066bb; font-weight: bold;\">saveUserPrivilegeAssignments<\/span><span style=\"color: #333333;\">(<\/span>\n        <span style=\"color: #555555; font-weight: bold;\">@RequestBody<\/span> List<span style=\"color: #333333;\">&lt;<\/span>Privilege<span style=\"color: #333333;\">&gt;<\/span> privileges<span style=\"color: #333333;\">,<\/span>\n        <span style=\"color: #555555; font-weight: bold;\">@PathVariable<\/span> Long userid<span style=\"color: #333333;\">)<\/span> <span style=\"color: #333333;\">{<\/span>\n    <span style=\"color: #008800; font-weight: bold;\">try<\/span> <span style=\"color: #333333;\">{<\/span>\n        userPrivilegeAssignmentService<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">deletePrivileges<\/span><span style=\"color: #333333;\">(<\/span>userid<span style=\"color: #333333;\">);<\/span>\n        List<span style=\"color: #333333;\">&lt;<\/span>Privilege<span style=\"color: #333333;\">&gt;<\/span> savedPrivileges <span style=\"color: #333333;\">=<\/span> userPrivilegeAssignmentService<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">savePrivileges<\/span><span style=\"color: #333333;\">(<\/span>privileges<span style=\"color: #333333;\">,<\/span> userid<span style=\"color: #333333;\">);<\/span>\n        <span style=\"color: #008800; font-weight: bold;\">return<\/span> ResponseEntity<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">status<\/span><span style=\"color: #333333;\">(<\/span>HttpStatus<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">CREATED<\/span><span style=\"color: #333333;\">).<\/span><span style=\"color: #0000cc;\">body<\/span><span style=\"color: #333333;\">(<\/span>savedPrivileges<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">toString<\/span><span style=\"color: #333333;\">());<\/span>\n    <span style=\"color: #333333;\">}<\/span> <span style=\"color: #008800; font-weight: bold;\">catch<\/span> <span style=\"color: #333333;\">(<\/span>Exception e<span style=\"color: #333333;\">)<\/span> <span style=\"color: #333333;\">{<\/span>\n        <span style=\"color: #008800; font-weight: bold;\">return<\/span> ResponseEntity<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">status<\/span><span style=\"color: #333333;\">(<\/span>HttpStatus<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">INTERNAL_SERVER_ERROR<\/span><span style=\"color: #333333;\">)<\/span>\n                <span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">body<\/span><span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"Failed to delete user privileges: \"<\/span> <span style=\"color: #333333;\">+<\/span> e<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">getMessage<\/span><span style=\"color: #333333;\">());<\/span>\n    <span style=\"color: #333333;\">}<\/span>\n<span style=\"color: #333333;\">}<\/span>\n<\/pre>\n<p>&nbsp;<\/p>\n<p>In the next part, we would understand the concept of <a href=\"https:\/\/kindsonthegenius.com\/blog\/inventoryms-springboot-roles-and-privileges-3-implementing-granted-authorities\/\" target=\"_blank\" rel=\"noopener\">Granted Authorities in Spring Boot<\/a>. Then we would use our API to set up access restriction to our API endpoints.<\/p>\n<h2>Frequently Asked Questions<\/h2>\n<p><strong>What are roles and privileges in SpringBoot?<\/strong><\/p>\n<p>Roles group related privileges, while privileges represent the specific permissions a user can have within an application.<\/p>\n<p><strong>What is the difference between the basic and fine-grained approach?<\/strong><\/p>\n<p>In the basic approach, a user assigned a role inherits all privileges associated with that role. The fine-grained approach allows individual privileges from different roles to be assigned directly to a user.<\/p>\n<p><strong>Why use a fine-grained approach for InventoryMS?<\/strong><\/p>\n<p>It provides more flexibility because a user can receive selected privileges from multiple roles rather than being limited to the complete privilege set of one role.<\/p>\n<p><strong>What is UserPrivilegeAssignment?<\/strong><\/p>\n<p><code>UserPrivilegeAssignment<\/code> is used to manage the relationship between users and their assigned privileges without relying on a direct many-to-many relationship.<\/p>\n<p><strong>Why is <code>savePrivileges<\/code> transactional?<\/strong><\/p>\n<p>The method first removes the user&#8217;s existing privilege assignments and then saves the new ones. Using a transaction ensures these operations are handled as one unit.<\/p>\n<p><strong>Can a user be assigned all privileges from a role?<\/strong><\/p>\n<p>Yes. The implementation supports assigning all privileges belonging to a specific role and removing those assignments when the role is unassigned.<\/p>\n<h2>Final Thoughts<\/h2>\n<p>Implementing roles and privileges is not just about deciding who can access an endpoint. The underlying data model determines how flexible and maintainable the authorization system will be as the application grows.<\/p>\n<p>For InventoryMS, the fine-grained approach provides that flexibility by allowing users to receive specific privileges from different roles. The <code>UserPrivilegeAssignment<\/code> model also keeps the relationships manageable while avoiding the complexity of a direct many-to-many design.<\/p>\n<p>The next important step is connecting these privileges to <strong>Granted Authorities<\/strong> in Spring Security. Once that is in place, the privileges defined in this model can be used to control access to specific API endpoints and application features.<\/p>\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to implement SpringBoot roles and privileges with a fine-grained data model, REST API endpoints, user privilege assignments, and role-based access management.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"pagelayer_contact_templates":[],"_pagelayer_content":"","footnotes":""},"categories":[414],"tags":[],"class_list":["post-1822","post","type-post","status-publish","format-standard","hentry","category-programming"],"acf":[],"_links":{"self":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/1822","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/comments?post=1822"}],"version-history":[{"count":5,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/1822\/revisions"}],"predecessor-version":[{"id":2528,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/1822\/revisions\/2528"}],"wp:attachment":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/media?parent=1822"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/categories?post=1822"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/tags?post=1822"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}