5.3.1 Securing requests
You need to ensure that requests for /design and /orders are available only to authenticated users; all other requests should be permitted for all users. The following configuration does exactly that:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeRequests()
.antMatchers("/design", "/orders").hasRole("USER")
.antMatchers("/", "/**").permitAll()
.and()
.build();
}The call to authorizeRequests() returns an object (ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry) on which you can specify URL paths and patterns and the security requirements for those paths. In this case, you specify the following two security rules:
- Requests for /design and /orders should be for users with a granted authority of
ROLE_USER. Don’t include theROLE_prefix on roles passed tohasRole(); it will be assumed byhasRole(). - All requests should be permitted to all users.
The order of these rules is important. Security rules declared first take precedence over those declared lower down. If you were to swap the order of those two security rules, all requests would have permitAll() applied to them; the rule for /design and /orders requests would have no effect.
The hasRole() and permitAll() methods are just a couple of the methods for declaring security requirements for request paths. Table 5.1 describes all the available methods.
Table 5.1 Configuration methods to define how a path is to be secured
| Method | What it does |
|---|---|
access(String) | Allows access if the given Spring Expression Language (SpEL) expression evaluates to true |
anonymous() | Allows access to anonymous users |
authenticated() | Allows access to authenticated users |
denyAll() | Denies access unconditionally |
fullyAuthenticated() | Allows access if the user is fully authenticated (not remembered) |
hasAnyAuthority(String...) | Allows access if the user has any of the given authorities |
hasAnyRole(String...) | Allows access if the user has any of the given roles |
hasAuthority(String) | Allows access if the user has the given authority |
hasIpAddress(String) | Allows access if the request comes from the given IP address |
hasRole(String) | Allows access if the user has the given role |
not() | Negates the effect of any of the other access methods |
permitAll() | Allows access unconditionally |
rememberMe() | Allows access for users who are authenticated via remember-me |
Most of the methods in table 5.1 provide essential security rules for request handling, but they’re self-limiting, enabling security rules only as defined by those methods. Alternatively, you can use the access() method to provide a SpEL expression to declare richer security rules. Spring Security extends SpEL to include several securityspecific values and functions, as listed in table 5.2.
Table 5.2 Spring Security extensions to the Spring Expression Language
| Security expression | What it evaluates to |
|---|---|
authentication | The user's authentication object |
denyAll | Always evaluates to false |
hasAnyAuthority(String… authorities) | true if the user has been granted any of the given authorities |
hasAnyRole(list of roles) | true if the user has any of the given roles |
hasAuthority(String authority) | true if the user has been granted the specified authority |
hasPermission(Object target, Object permission) | true if the user has access to the specified target object for the given permission |
hasPermission(Object target, String targetType, Object permission) | true if the user has access to the object specified by targetId and the specified targetType for the given permission |
hasRole(role) | true if the user has the given role |
hasIpAddress(IP Address) | true if the request comes from the given IP address |
isAnonymous() | true if the user is anonymous |
isAuthenticated() | true if the user is authenticated |
isFullyAuthenticated() | true if the user is fully authenticated (not authenticated with remember-me) |
isRememberMe() | true if the user is authenticated via remember-me |
permitAll() | Always evaluates to true |
principal | The user's principal object |
As you can see, most of the security expression extensions in table 5.2 correspond to similar methods in table 5.1. In fact, using the access() method along with the hasRole() and permitAll expressions, you can rewrite the SecurityFilterChain configuration as follows.
Listing 5.7 Using Spring expressions to define authorization rules
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeRequests()
.antMatchers("/design", "/orders").access("hasRole('USER')")
.antMatchers("/", "/**").access("permitAll()")
.and()
.build();
}This may not seem like a big deal at first. After all, these expressions only mirror what you already did with method calls. But expressions can be much more flexible. For instance, suppose that (for some crazy reason) you wanted to allow only users with ROLE_USER authority to create new tacos on Tuesdays (for example, on Taco Tuesday); you could rewrite the expression as shown in this modified version of the SecurityFilterChain bean method:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeRequests()
.antMatchers("/design", "/orders")
.access("hasRole('USER') && " +
"T(java.util.Calendar).getInstance().get("+
"T(java.util.Calendar).DAY_OF_WEEK) == " +
"T(java.util.Calendar).TUESDAY")
.antMatchers("/", "/**").access("permitAll")
.and()
.build();
}With SpEL security constraints, the possibilities are virtually endless. I’ll bet that you’re already dreaming up interesting security constraints based on SpEL.
The authorization needs for the Taco Cloud application are met by the simple use of access() and the SpEL expressions. Now let’s see about customizing the login page to fit the look of the Taco Cloud application.
