Securing Spring Boot Applications - From Requirements to Implementation

tags

Security is a fundamental aspect of any application, but the right security approach depends heavily on your specific needs. When our team was tasked with developing a Construction Project Diary system, we needed a security model that could handle different user types—from construction workers to administrators—each with their own specific responsibilities and access rights.

After analyzing project’s requirements, we debated using Access Control List (ACL) and Role-Based Access Control (RBAC) as our primary security approach. While ACL better matched user’s requirements, in the end we chose RBAC because of time and budgetary constraints. We eventually switched back to ACL.

In this article series, I’ll share our journey of implementing and validating this security model in Spring Boot. We’ll explore how we structured our permissions, implemented endpoint security, and developed tools to ensure consistent security coverage across our application. Lastly, we will discuss how we eventually transitioned back to ACL.

Access control methods

Authorizing what users can do / not do in an application is called access control. A great source comparing access control types is the article What is role-based access control (RBAC)?.

The most typical one is Role-Based Access Control (RBAC), where we define roles of the user types and how they can use the product. It is usually also the easiest to implement. RBAC allowed us to map user professions directly to security roles, making it both intuitive for users and maintainable for developers.

The more complex option is Access Control List (ACL), where we define authorities of users per object they are trying to access. It requires more orchestration in terms of storing the connection of members of the object and their authorities.

Construction Project Diary

At my current job, we were tasked with implementing a Construction Project Diary. The system consists of a web administrative portal and a mobile application. Users are separated into three main groups: Administrators, Supervisors, and Workers. These form the basis of the roles in the application. The whole application however has about 20 different roles.

After the discussions with the customer, we chose Role-Based Access Control even though we later regretted the decision, since Access Control List would be more suitable. Each role consists of a set of authorities.

Authorities

Each specific operation that a user can perform in our system is represented by an authority, and we construct these authorities by combining two essential elements: a module and a scope.

For example, when a construction supervisor needs to approve a daily log entry, they would need an authority that combines the “daily-log” module with an “approve” scope. This creates a clear, descriptive permission: “daily-log:approve”. By breaking down permissions this way, we can precisely control what each user can do within specific parts of our system.

Think of modules as different sections of our application (like daily logs, user management, or equipment tracking), and scopes as the types of actions that can be performed (like viewing, editing, or approving). This separation allows us to create flexible, reusable permission combinations that map naturally to our business requirements.

For the complete technical implementation, including our code structure and how we define different permission scopes, continue reading Building a Flexible Permission System.

Implementing Security Checks

After establishing our authority structure, the next crucial decision was determining where and how to implement security checks in our application. In Spring Boot, we can enforce security at two distinct levels: at the controller level (protecting specific endpoints) or at the method level (securing individual service methods).

This choice significantly impacts both our code organization and security enforcement. Think of it like securing a building - we could either place security guards at each entrance (controller-level security) or require key cards for each individual room (method-level security). Each approach has its own strengths and trade-offs.

We ultimately chose controller-level security for our Construction Project Diary system. This decision was driven by three key factors:

  1. It allows us to implement a strict “deny by default” policy, where every endpoint must be explicitly granted access. This is similar to starting with a locked building and deliberately choosing which doors to open, rather than risking leaving any entrance unguarded.

  2. We could separate our security rules from our business logic, making both easier to understand and test. Just as a building’s security system can be managed independently of the activities happening inside each room, our security configuration stands apart from our application code.

  3. Our security rules could be defined using Spring’s Expression Language in Java code rather than string-based annotations, giving us better compile-time safety and IDE support. This means we catch security configuration errors earlier, during development rather than at runtime.

For the detailed implementation of these security checks, including our custom validation system that ensures no endpoint goes unprotected, continue reading Implementing Endpoint Security in Spring Boot.

References

What is role-based access control (RBAC)? Building a Flexible Permission System Implementing Endpoint Security in Spring Boot