Spring Security (Spring Boot)
Introduction
Spring Security authentication, authorization and hierarchical authorities configuration.
Subpages
Manual authentication, custom authorization w/ OAuth & hierarchical authorities configuration (Spring Boot)
Manual authentication, custom authorization w/ JWT & hierarchical authorities configuration (Spring Boot)
Reference
Spring Security: Authorize HTTP Requests
https://docs.spring.io/spring-security/reference/servlet/authorization/authorize-http-requests.html
Spring Security Expressions
hasRole, hasAnyRole
Remark: hasRole('ROLE_ADMIN') ~ hasRole(‘ADMIN') because the ‘ROLE_‘ prefix gets added automatically.
hasRole('ADMIN')
hasAnyRole('ADMIN','USER')
hasAuthority, hasAnyAuthority
Remark: hasAuthority('ROLE_ADMIN') ~ hasRole('ROLE_ADMIN')
hasAuthority("ADMIN")
hasAnyAuthority("ADMIN", "USER")
permitAll, denyAll
permitAll() // both anonymous and logged in
denyAll()
isAnonymous, isAuthenticated, isRememberMe, isFullyAuthenticated
isAnonymous()
isAuthenticated()
isRememberMe() // Rember Me functionality using cookies
isFullyAuthenticated() // If the user isn't an anonymous or remember-me user
principal, authentication
Expressions that, respectively, allow to access the principal object representing the current authorized (or anonymous) user and the current Authentication object from the SecurityContext.
hasPermission
It allows to specify authorization constraints on individual domain objects based on abstract permissions.
hasPermission(Object target, Object permission)
hasPermission(Object targetId, String targetType, Object permission)
POM configuration
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
SecurityFilterChain configuration (Spring Boot >= 3.0)
WebSecurityConfig
package edu.uoc.gpradoc;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.firewall.StrictHttpFirewall;
import jakarta.inject.Inject;
/**
* Note: Order lower values have higher priority. Higher values will only execute if no adapter with
* lower value matches.
*/
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
/** Data REST base path */
private String basePathDataRest;
/**
* Constructor
*
* @param basePathDataRest -
*
*/
@Inject
public WebSecurityConfig(
@Value("${spring.data.rest.base-path:'/merida'}") String basePathDataRest) {
super();
this.basePathDataRest = basePathDataRest;
}
/**
* Configuration for allowing special characters, e.g: ';', '\', '/' and '%'.
* @return -
*/
@Bean
WebSecurityCustomizer webSecurityCustomizer() {
StrictHttpFirewall firewall = new StrictHttpFirewall();
// symbol '/' encoded '%2F' [didn't work w/ sb-3.1.3 (uses Tomcat-10.1.12)]
firewall.setAllowUrlEncodedSlash(true);
// symbol '\'
firewall.setAllowBackSlash(true);
// symbol ';'
firewall.setAllowSemicolon(true);
// symbol '%'
firewall.setAllowUrlEncodedPercent(true);
return web -> web.httpFirewall(firewall);
}
/**
* @param http
* @return -
* @throws Exception
*/
@Order(4)
@Bean
SecurityFilterChain filterChain4(HttpSecurity http) throws Exception {
/*- DOC:
* Default user and pass is configured in application.properties (spring.security.user.*).
*/
http// sb3
.securityMatcher(basePathDataRest + "/**") // Apply only if match
.authorizeHttpRequests(authorize -> authorize//
.anyRequest().authenticated() //
)//
.httpBasic(basic -> basic.realmName("GPRA_docback"))//
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))//
;
return http.build();
}
/**
* @param http
* @return -
* @throws Exception
*/
@Order(5)
@Bean
SecurityFilterChain filterChain5(HttpSecurity http) throws Exception {
/*- DOC:
* Default user and pass is configured in application.properties (spring.security.user.*).
*/
http// sb3
.securityMatcher("/actuator", "/actuator/**") // Apply only if match
.authorizeHttpRequests(authorize -> authorize//
.anyRequest().authenticated() //
)//
.httpBasic().realmName("GPRA_docback")//
.and()//
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)//
;
return http.build();
}
/**
* Springdoc v2 (for Spring Boot >= 3.0).
*
* @param http
* @return -
* @throws Exception
*/
@SuppressWarnings({"java:S1612"})
@Order(6)
@Bean
SecurityFilterChain filterChainSpringDocV2(HttpSecurity http) throws Exception {
final String[] pathAnonymous = // NOSONAR (SONARJAVA-3991)
{ "/swagger-ui.html", "/swagger-ui/**", "/v3/api-docs/**" };
http// sb3
.securityMatcher(pathAnonymous) // only invoke if matching
.authorizeHttpRequests(authorize -> authorize//
.anyRequest().anonymous()//
) //
;
http.csrf(csrf -> csrf.disable())//
.headers(headers -> headers.frameOptions(fo -> fo.disable()));//
// DOC. Avoid generation of cookie JSESSIONID (Swagger)
http.sessionManagement(sm ->
sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
return http.build();
}
/**
* Other anonymous.
*
* @param http
* @return -
* @throws Exception
*/
@Order(7)
@Bean
SecurityFilterChain filterChainOtherAnonymous(HttpSecurity http) throws Exception {
final String[] pathAnonymous = { "/ui/**", "/monitor/**", "/tech/**", "/favicon*", "/version", "/csrf" };
http// sb3
.securityMatcher(pathAnonymous) // Apply only if match
.authorizeHttpRequests(authorize -> authorize//
.anyRequest().anonymous()//
) //
;
http.csrf().disable();
http.headers().frameOptions().disable();
// DOC. Avoid generation of cookie JSESSIONID (Swagger)
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
return http.build();
}
}