CodeGym /Courses /Module 5. Spring /User roles and access control: @Secured annotation

User roles and access control: @Secured annotation

Module 5. Spring
Level 17 , Lesson 4
Available

In the world of web apps, users aren't just abstract "people". Each user can be assigned a role that defines what actions they can perform. This is a crucial part of security because it enforces strict separation of access to data and functionality.

Imagine you're building a banking app: a client can view their accounts, transfer funds, but can't, say, generate bank reports. An administrator, however, can. To manage this separation at the code level, we use a role-based access system. In Spring Security this is done with the @Secured annotation.

The @Secured annotation lets you control access to methods or resources based on user roles. You can use it to restrict access at the service, controller, or even individual business-method level.

Official docs: Spring Security: @Secured


Configuring roles and security using @Secured

Let's break this down step by step.

1. Project setup

Let's create a simple Spring Boot app where we'll work with users and roles. Make sure you have Spring Security on the classpath.

Add the dependencies to pom.xml


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>

Security configuration

To use @Secured you need to enable method-level security.


import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true) // Enable @Secured support
public class SecurityConfig {
    // In this lecture we use the built-in user configuration (InMemoryUserDetailsManager),
    // We'll cover more advanced DB-backed examples later.
}

2. Define roles and users

For testing, let's create roles and users in memory (InMemoryUserDetailsManager).

Define users and roles:


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
public class UserConfig {

    @Bean
    public InMemoryUserDetailsManager userDetailsManager() {
        UserDetails admin = User.builder()
            .username("admin")
            .password(passwordEncoder().encode("admin123"))
            .roles("ADMIN") // Administrator role
            .build();

        UserDetails user = User.builder()
            .username("user")
            .password(passwordEncoder().encode("user123"))
            .roles("USER") // User role
            .build();

        return new InMemoryUserDetailsManager(admin, user);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(); // We encrypt passwords
    }
}
Passwords must be encrypted! We'll use BCryptPasswordEncoder for that.

3. Using @Secured in services

Let's create a simple service and restrict access to its methods based on roles.

Implement the service:


import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Service;

@Service
public class MyService {

    @Secured("ROLE_ADMIN") // Access for administrators only
    public String adminMethod() {
        return "Hey, Administrator!";
    }

    @Secured("ROLE_USER") // Access for users only
    public String userMethod() {
        return "Hey, User!";
    }
}

Note that roles should be prefixed with ROLE_. For example, ROLE_ADMIN. That's the Spring Security convention.

4. Create a controller for testing

Now let's create a REST controller that uses our service.


import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    private final MyService myService;

    public MyController(MyService myService) {
        this.myService = myService;
    }

    @GetMapping("/admin")
    public String adminEndpoint() {
        return myService.adminMethod();
    }

    @GetMapping("/user")
    public String userEndpoint() {
        return myService.userMethod();
    }
}

5. Test the app

Run the app and test:

  1. Open Postman or just use your browser.
  2. Try to hit /admin and /user.

If you log in as admin, access to /admin will be allowed, and /user — denied. For user — the opposite.

6. Add multiple roles to one method

If a method should be available to multiple roles, you can list them as an array:


@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
public String managerOrAdminMethod() {
    return "Hey, Manager or Administrator!";
}

Spring Security will check whether the user has at least one of the listed roles.


Gotchas and common mistakes

  1. Roles must have the ROLE_ prefix. Spring Security expects roles to start with ROLE_. If you don't do this, it won't work. For example, using ADMIN instead of ROLE_ADMIN won't work.
  2. Getting a 403 Forbidden. If you see this error, make sure that:
    • @Secured support is enabled via @EnableGlobalMethodSecurity(securedEnabled = true).
    • The user's role is specified correctly (including the ROLE_ prefix).
  3. Don't put role logic in controllers without a good reason. It's better to enforce security at the service layer. That helps minimize duplicated logic.

Practical usage

Using roles and access rights is a basic but very powerful tool for controlling access in applications. It's used everywhere: from small online stores to complex enterprise systems. So understanding how @Secured works isn't just useful — it's essential.

For more advanced cases we'll cover @PreAuthorize and @PostAuthorize in upcoming lectures — they let you build more flexible access rules using SpEL (Spring Expression Language).

Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION