Note
|
|
This section builds on Servlet Architecture and Implementation by digging deeper into how authorization works within Servlet-based applications.
The {security-api-url}org/springframework/security/web/access/intercept/FilterSecurityInterceptor.html[FilterSecurityInterceptor
] provides authorization for HttpServletRequest
instances.
It is inserted into the FilterChainProxy as one of the Security Filters.
The following image shows the role of FilterSecurityInterceptor
:
The FilterSecurityInterceptor
obtains an Authentication from the SecurityContextHolder.
FilterSecurityInterceptor
creates a {security-api-url}org/springframework/security/web/FilterInvocation.html[FilterInvocation
] from the HttpServletRequest
, HttpServletResponse
, and FilterChain
that are passed into the FilterSecurityInterceptor
.
It passes the FilterInvocation
to SecurityMetadataSource
to get the ConfigAttribute
s.
It passes the Authentication
, FilterInvocation
, and ConfigAttribute
s to the AccessDecisionManager
.
If authorization is denied, an AccessDeniedException
is thrown.
In this case, the ExceptionTranslationFilter
handles the AccessDeniedException
.
If access is granted, FilterSecurityInterceptor
continues with the FilterChain
, which lets the application process normally.
By default, Spring Security’s authorization requires all requests to be authenticated. The following listing shows the explicit configuration:
We can configure Spring Security to have different rules by adding more rules in order of precedence:
- Java
-
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... .authorizeRequests(authorize -> authorize // (1) .requestMatchers("/resources/**", "/signup", "/about").permitAll() // (2) .requestMatchers("/admin/**").hasRole("ADMIN") // (3) .requestMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')") // (4) .anyRequest().denyAll() // (5) ); return http.build(); }
- XML
-
<http> <!--(1)--> <!-- ... --> <!--(2)--> <intercept-url pattern="/resources/**" access="permitAll"/> <intercept-url pattern="/signup" access="permitAll"/> <intercept-url pattern="/about" access="permitAll"/> <intercept-url pattern="/admin/**" access="hasRole('ADMIN')"/> <!--(3)--> <intercept-url pattern="/db/**" access="hasRole('ADMIN') and hasRole('DBA')"/> <!--(4)--> <intercept-url pattern="/**" access="denyAll"/> <!--(5)--> </http>
- Kotlin
-
@Bean open fun filterChain(http: HttpSecurity): SecurityFilterChain { http { authorizeRequests { // (1) authorize("/resources/**", permitAll) // (2) authorize("/signup", permitAll) authorize("/about", permitAll) authorize("/admin/**", hasRole("ADMIN")) // (3) authorize("/db/**", "hasRole('ADMIN') and hasRole('DBA')") // (4) authorize(anyRequest, denyAll) // (5) } } return http.build() }
-
There are multiple authorization rules specified. Each rule is considered in the order they were declared.
-
We specified multiple URL patterns that any user can access. Specifically, any user can access a request if the URL starts with "/resources/", equals "/signup", or equals "/about".
-
Any URL that starts with "/admin/" will be restricted to users who have the role "ROLE_ADMIN". You will notice that since we are invoking the
hasRole
method we do not need to specify the "ROLE_" prefix. -
Any URL that starts with "/db/" requires the user to have both "ROLE_ADMIN" and "ROLE_DBA". You will notice that since we are using the
hasRole
expression we do not need to specify the "ROLE_" prefix. -
Any URL that has not already been matched on is denied access. This is a good strategy if you do not want to accidentally forget to update your authorization rules.
By default, the FilterSecurityInterceptor
applies to every request.
This means that if a request is dispatched from a request that was already filtered, the FilterSecurityInterceptor
will perform the same authorization checks on the dispatched request.
In some scenarios, you may not want to apply authorization on some dispatcher types:
- Java
-
@Bean SecurityFilterChain web(HttpSecurity http) throws Exception { http .authorizeRequests((authorize) -> authorize .dispatcherTypeMatchers(DispatcherType.ASYNC, DispatcherType.ERROR).permitAll() .anyRequest.authenticated() ) // ... return http.build(); }
- XML
-
<http auto-config="true"> <intercept-url request-matcher-ref="dispatcherTypeMatcher" access="permitAll" /> <intercept-url pattern="/**" access="authenticated"/> </http> <b:bean id="dispatcherTypeMatcher" class="org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher"> <b:constructor-arg value="ASYNC"/> <b:constructor-arg value="ERROR"/> </b:bean>