Information Security 7 min read

Mastering Spring Security: Fine-Grained Method Permissions with @PreAuthorize

This tutorial demonstrates how to secure Spring Boot REST endpoints using Spring Security, covering URL‑based rules, enabling method‑level security, and applying @PreAuthorize, @RolesAllowed, and @Secured annotations for precise access control.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Mastering Spring Security: Fine-Grained Method Permissions with @PreAuthorize

Spring Security Permission Control Series (6)

Environment: Spring Boot 2.4.12 + Spring Security 5.4.9

Demo Controller

<code>@RestController
@RequestMapping("/business")
public class BussinessController {
    @GetMapping("/{id}")
    public Object get(@PathVariable("id") Integer id) {
        return "receive - " + id ;
    }
}
</code>

Security Configuration (URL‑based)

<code>@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests().antMatchers("/resources/**", "/cache/**", "/process/login").permitAll();
        http.authorizeRequests().antMatchers("/demos/**").hasRole("USERS");
        http.authorizeRequests().antMatchers("/api/**").hasRole("ADMIN");
        // Require authentication for all /business/** requests
        http.authorizeRequests().antMatchers("/business/**").authenticated();
    }
}
</code>

After this configuration, accessing http://localhost:8080/business/100 prompts for login; once authenticated, the endpoint is reachable.

Method‑Level Security

Enable annotation‑based security on methods:

<code>@Configuration
@EnableGlobalMethodSecurity(jsr250Enabled = true, prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}
</code>

Key attributes:

jsr250Enabled : enables support for JSR‑250 annotations such as @RolesAllowed .

prePostEnabled : enables expression‑based annotations like @PreAuthorize and @PostAuthorize .

securedEnabled : enables the @Secured annotation.

Annotation Examples

<code>@GetMapping("/{id}")
@RolesAllowed("ROLE_USERS") // ① can specify multiple roles as a String[]
@Secured("ROLE_USERS1")   // ② can also specify multiple roles
@PreAuthorize("hasRole('USERS')") // ③ supports SpEL expressions
public Object get(@PathVariable("id") Integer id) {
    return "receive - " + id ;
}
</code>

Only the @PreAuthorize example is demonstrated here; the other two are straightforward.

Using @PreAuthorize

The annotation evaluates an expression to decide whether the method may be invoked. Common expressions include:

hasRole('USERS') – the caller must have the USERS role.

hasAnyRole('USERS','ADMIN') – the caller needs any of the listed roles.

hasAuthority('bus:news:see') – the caller must possess the specific authority.

hasAnyAuthority('bus:news:see','bus:news:write') – any listed authority is sufficient.

These expressions are evaluated by SecurityExpressionRoot :

<code>public abstract class SecurityExpressionRoot implements SecurityExpressionOperations {
    private String defaultRolePrefix = "ROLE_";
    @Override
    public final boolean hasRole(String role) {
        return hasAnyRole(role);
    }
    @Override
    public final boolean hasAnyRole(String... roles) {
        return hasAnyAuthorityName(this.defaultRolePrefix, roles);
    }
    @Override
    public final boolean hasAuthority(String authority) {
        return hasAnyAuthority(authority);
    }
    @Override
    public final boolean hasAnyAuthority(String... authorities) {
        return hasAnyAuthorityName(null, authorities);
    }
    private boolean hasAnyAuthorityName(String prefix, String... roles) {
        Set<String> roleSet = getAuthoritySet();
        for (String role : roles) {
            String defaultedRole = getRoleWithDefaultPrefix(prefix, role);
            if (roleSet.contains(defaultedRole)) {
                return true;
            }
        }
        return false;
    }
}
</code>

Both hasRole and hasAuthority ultimately delegate to hasAnyAuthorityName , with hasRole automatically adding the ROLE_ prefix.

Summary

The article covered various ways to control access to business‑level controller endpoints, including URL‑based rules and fine‑grained method‑level annotations such as @PreAuthorize , @RolesAllowed , and @Secured . The next article will explore custom authentication/authorization and advanced @PreAuthorize usage.

JavaBackend DevelopmentSpring SecurityMethod SecurityPreAuthorize
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.