authorize-requests.adoc 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. [[servlet-authorization-filtersecurityinterceptor]]
  2. = Authorize HttpServletRequest with FilterSecurityInterceptor
  3. :figures: servlet/authorization
  4. [NOTE]
  5. `FilterSecurityInterceptor` is in the process of being replaced by xref:servlet/authorization/authorize-http-requests.adoc[`AuthorizationFilter`].
  6. Consider using that instead.
  7. This section builds on xref:servlet/architecture.adoc#servlet-architecture[Servlet Architecture and Implementation] by digging deeper into how xref:servlet/authorization/index.adoc#servlet-authorization[authorization] works within Servlet based applications.
  8. The {security-api-url}org/springframework/security/web/access/intercept/FilterSecurityInterceptor.html[`FilterSecurityInterceptor`] provides xref:servlet/authorization/index.adoc#servlet-authorization[authorization] for ``HttpServletRequest``s.
  9. It is inserted into the xref:servlet/architecture.adoc#servlet-filterchainproxy[FilterChainProxy] as one of the xref:servlet/architecture.adoc#servlet-security-filters[Security Filters].
  10. .Authorize HttpServletRequest
  11. [.invert-dark]
  12. image::{figures}/filtersecurityinterceptor.png[]
  13. * image:{icondir}/number_1.png[] First, the `FilterSecurityInterceptor` obtains an xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[Authentication] from the xref:servlet/authentication/architecture.adoc#servlet-authentication-securitycontextholder[SecurityContextHolder].
  14. * image:{icondir}/number_2.png[] Second, `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`.
  15. // FIXME: link to FilterInvocation
  16. * image:{icondir}/number_3.png[] Next, it passes the `FilterInvocation` to `SecurityMetadataSource` to get the ``ConfigAttribute``s.
  17. * image:{icondir}/number_4.png[] Finally, it passes the `Authentication`, `FilterInvocation`, and ``ConfigAttribute``s to the xref:servlet/authorization.adoc#authz-access-decision-manager`AccessDecisionManager`.
  18. ** image:{icondir}/number_5.png[] If authorization is denied, an `AccessDeniedException` is thrown.
  19. In this case the xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] handles the `AccessDeniedException`.
  20. ** image:{icondir}/number_6.png[] If access is granted, `FilterSecurityInterceptor` continues with the xref:servlet/architecture.adoc#servlet-filters-review[FilterChain] which allows the application to process normally.
  21. // configuration (xml/java)
  22. By default, Spring Security's authorization will require all requests to be authenticated.
  23. The explicit configuration looks like:
  24. [[servlet-authorize-requests-defaults]]
  25. .Every Request Must be Authenticated
  26. [tabs]
  27. ======
  28. Java::
  29. +
  30. [source,java,role="primary"]
  31. ----
  32. @Bean
  33. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  34. http
  35. // ...
  36. .authorizeRequests(authorize -> authorize
  37. .anyRequest().authenticated()
  38. );
  39. return http.build();
  40. }
  41. ----
  42. XML::
  43. +
  44. [source,xml,role="secondary"]
  45. ----
  46. <http>
  47. <!-- ... -->
  48. <intercept-url pattern="/**" access="authenticated"/>
  49. </http>
  50. ----
  51. Kotlin::
  52. +
  53. [source,kotlin,role="secondary"]
  54. ----
  55. @Bean
  56. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  57. http {
  58. // ...
  59. authorizeRequests {
  60. authorize(anyRequest, authenticated)
  61. }
  62. }
  63. return http.build()
  64. }
  65. ----
  66. ======
  67. We can configure Spring Security to have different rules by adding more rules in order of precedence.
  68. .Authorize Requests
  69. [tabs]
  70. ======
  71. Java::
  72. +
  73. [source,java,role="primary"]
  74. ----
  75. @Bean
  76. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  77. http
  78. // ...
  79. .authorizeRequests(authorize -> authorize // <1>
  80. .mvcMatchers("/resources/**", "/signup", "/about").permitAll() // <2>
  81. .mvcMatchers("/admin/**").hasRole("ADMIN") // <3>
  82. .mvcMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')") // <4>
  83. .anyRequest().denyAll() // <5>
  84. );
  85. return http.build();
  86. }
  87. ----
  88. XML::
  89. +
  90. [source,xml,role="secondary"]
  91. ----
  92. <http> <!--1-->
  93. <!-- ... -->
  94. <!--2-->
  95. <intercept-url pattern="/resources/**" access="permitAll"/>
  96. <intercept-url pattern="/signup" access="permitAll"/>
  97. <intercept-url pattern="/about" access="permitAll"/>
  98. <intercept-url pattern="/admin/**" access="hasRole('ADMIN')"/> <!--3-->
  99. <intercept-url pattern="/db/**" access="hasRole('ADMIN') and hasRole('DBA')"/> <!--4-->
  100. <intercept-url pattern="/**" access="denyAll"/> <!--5-->
  101. </http>
  102. ----
  103. Kotlin::
  104. +
  105. [source,kotlin,role="secondary"]
  106. ----
  107. @Bean
  108. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  109. http {
  110. authorizeRequests { // <1>
  111. authorize("/resources/**", permitAll) // <2>
  112. authorize("/signup", permitAll)
  113. authorize("/about", permitAll)
  114. authorize("/admin/**", hasRole("ADMIN")) // <3>
  115. authorize("/db/**", "hasRole('ADMIN') and hasRole('DBA')") // <4>
  116. authorize(anyRequest, denyAll) // <5>
  117. }
  118. }
  119. return http.build()
  120. }
  121. ----
  122. ======
  123. <1> There are multiple authorization rules specified.
  124. Each rule is considered in the order they were declared.
  125. <2> We specified multiple URL patterns that any user can access.
  126. Specifically, any user can access a request if the URL starts with "/resources/", equals "/signup", or equals "/about".
  127. <3> Any URL that starts with "/admin/" will be restricted to users who have the role "ROLE_ADMIN".
  128. You will notice that since we are invoking the `hasRole` method we do not need to specify the "ROLE_" prefix.
  129. <4> Any URL that starts with "/db/" requires the user to have both "ROLE_ADMIN" and "ROLE_DBA".
  130. You will notice that since we are using the `hasRole` expression we do not need to specify the "ROLE_" prefix.
  131. <5> Any URL that has not already been matched on is denied access.
  132. This is a good strategy if you do not want to accidentally forget to update your authorization rules.
  133. [[filtersecurityinterceptor-every-request]]
  134. == Apply FilterSecurityInterceptor to every request
  135. By default, the `FilterSecurityInterceptor` only applies once to a request.
  136. This means that if a request is dispatched from a request that was already filtered, the `FilterSecurityInterceptor` will back-off and not perform any authorization checks.
  137. In some scenarios, you may want to apply the filter to every request.
  138. You can configure Spring Security to apply the authorization rules to every request by using the `filterSecurityInterceptorOncePerRequest` method:
  139. .Set filterSecurityInterceptorOncePerRequest to false
  140. [tabs]
  141. ======
  142. Java::
  143. +
  144. [source,java,role="primary"]
  145. ----
  146. @Bean
  147. SecurityFilterChain web(HttpSecurity http) throws Exception {
  148. http
  149. .authorizeRequests((authorize) -> authorize
  150. .filterSecurityInterceptorOncePerRequest(false)
  151. .anyRequest.authenticated()
  152. )
  153. // ...
  154. return http.build();
  155. }
  156. ----
  157. XML::
  158. +
  159. [source,xml,role="secondary"]
  160. ----
  161. <http once-per-request="false">
  162. <intercept-url pattern="/**" access="authenticated"/>
  163. </http>
  164. ----
  165. ======
  166. You can also configure authorization based on the request dispatcher type:
  167. .Permit ASYNC dispatcher type
  168. [tabs]
  169. ======
  170. Java::
  171. +
  172. [source,java,role="primary"]
  173. ----
  174. @Bean
  175. SecurityFilterChain web(HttpSecurity http) throws Exception {
  176. http
  177. .authorizeRequests((authorize) -> authorize
  178. .filterSecurityInterceptorOncePerRequest(false)
  179. .dispatcherTypeMatchers(DispatcherType.ASYNC).permitAll()
  180. .anyRequest.authenticated()
  181. )
  182. // ...
  183. return http.build();
  184. }
  185. ----
  186. XML::
  187. +
  188. [source,xml,role="secondary"]
  189. ----
  190. <http auto-config="true" once-per-request="false">
  191. <intercept-url request-matcher-ref="dispatcherTypeMatcher" access="permitAll" />
  192. <intercept-url pattern="/**" access="authenticated"/>
  193. </http>
  194. <b:bean id="dispatcherTypeMatcher" class="org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher">
  195. <b:constructor-arg value="ASYNC"/>
  196. </b:bean>
  197. ----
  198. ======