| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156 | 
							- [[servlet-authorization-authorizationfilter]]
 
- = Authorize HttpServletRequests
 
- :figures: servlet/authorization
 
- Spring Security allows you to xref:servlet/authorization/index.adoc[model your authorization] at the request level.
 
- For example, with Spring Security you can say that all pages under `/admin` require one authority while all other pages simply require authentication.
 
- By default, Spring Security requires that every request be authenticated.
 
- That said, any time you use xref:servlet/configuration/java.adoc#jc-httpsecurity[an `HttpSecurity` instance], it's necessary to declare your authorization rules.
 
- [[activate-request-security]]
 
- Whenever you have an `HttpSecurity` instance, you should at least do:
 
- .Use authorizeHttpRequests
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- http
 
-     .authorizeHttpRequests((authorize) -> authorize
 
-         .anyRequest().authenticated()
 
-     )
 
- ----
 
- Kotlin::
 
- +
 
- [source,kotlin,role="secondary"]
 
- ----
 
- http {
 
-     authorizeHttpRequests {
 
-         authorize(anyRequest, authenticated)
 
-     }
 
- }
 
- ----
 
- Xml::
 
- +
 
- [source,xml,role="secondary"]
 
- ----
 
- <http>
 
-     <intercept-url pattern="/**" access="authenticated"/>
 
- </http>
 
- ----
 
- ======
 
- This tells Spring Security that any endpoint in your application requires that the security context at a minimum be authenticated in order to allow it.
 
- In many cases, your authorization rules will be more sophisticated than that, so please consider the following use cases:
 
- * I have an app that uses `authorizeRequests` and I want to <<migrate-authorize-requests,migrate it to `authorizeHttpRequests`>>
 
- * I want to <<request-authorization-architecture,understand how the `AuthorizationFilter` components work>>
 
- * I want to <<match-requests, match requests>> based on a pattern; specifically <<match-by-regex,regex>>
 
- * I want to match request, and I map Spring MVC to <<mvc-not-default-servlet, something other than the default servlet>>
 
- * I want to <<authorize-requests, authorize requests>>
 
- * I want to <<match-by-custom, match a request programmatically>>
 
- * I want to <<authorize-requests, authorize a request programmatically>>
 
- * I want to <<remote-authorization-manager, delegate request authorization>> to a policy agent
 
- [[request-authorization-architecture]]
 
- == Understanding How Request Authorization Components Work
 
- [NOTE]
 
- 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 at the request level in Servlet-based applications.
 
- .Authorize HttpServletRequest
 
- image::{figures}/authorizationfilter.png[]
 
- * image:{icondir}/number_1.png[] First, the `AuthorizationFilter` constructs a `Supplier` that retrieves an  xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[Authentication] from the xref:servlet/authentication/architecture.adoc#servlet-authentication-securitycontextholder[SecurityContextHolder].
 
- * image:{icondir}/number_2.png[] Second, it passes the `Supplier<Authentication>` and the `HttpServletRequest` to the xref:servlet/architecture.adoc#authz-authorization-manager[`AuthorizationManager`].
 
- The `AuthorizationManager` matches the request to the patterns in `authorizeHttpRequests`, and runs the corresponding rule.
 
- ** image:{icondir}/number_3.png[] If authorization is denied, xref:servlet/authorization/events.adoc[an `AuthorizationDeniedEvent` is published], and an `AccessDeniedException` is thrown.
 
- In this case the xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] handles the `AccessDeniedException`.
 
- ** image:{icondir}/number_4.png[] If access is granted, xref:servlet/authorization/events.adoc[an `AuthorizationGrantedEvent` is published] and `AuthorizationFilter` continues with the xref:servlet/architecture.adoc#servlet-filters-review[FilterChain] which allows the application to process normally.
 
- === `AuthorizationFilter` Is Last By Default
 
- The `AuthorizationFilter` is last in xref:servlet/architecture.adoc#servlet-filterchain-figure[the Spring Security filter chain] by default.
 
- This means that Spring Security's xref:servlet/authentication/index.adoc[authentication filters], xref:servlet/exploits/index.adoc[exploit protections], and other filter integrations do not require authorization.
 
- If you add filters of your own before the `AuthorizationFilter`, they will also not require authorization; otherwise, they will.
 
- A place where this typically becomes important is when you are adding {spring-framework-reference-url}web.html#spring-web[Spring MVC] endpoints.
 
- Because they are executed by the {spring-framework-reference-url}web.html#mvc-servlet[`DispatcherServlet`] and this comes after the `AuthorizationFilter`, your endpoints need to be <<authorizing-endpoints,included in `authorizeHttpRequests` to be permitted>>.
 
- === All Dispatches Are Authorized
 
- The `AuthorizationFilter` runs not just on every request, but on every dispatch.
 
- This means that the `REQUEST` dispatch needs authorization, but also ``FORWARD``s, ``ERROR``s, and ``INCLUDE``s.
 
- For example, {spring-framework-reference-url}web.html#spring-web[Spring MVC] can `FORWARD` the request to a view resolver that renders a Thymeleaf template, like so:
 
- .Sample Forwarding Spring MVC Controller
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- @Controller
 
- public class MyController {
 
-     @GetMapping("/endpoint")
 
-     public String endpoint() {
 
-         return "endpoint";
 
-     }
 
- }
 
- ----
 
- Kotlin::
 
- +
 
- [source,kotlin,role="secondary"]
 
- ----
 
- @Controller
 
- class MyController {
 
-     @GetMapping("/endpoint")
 
-     fun endpoint(): String {
 
-         return "endpoint"
 
-     }
 
- }
 
- ----
 
- ======
 
- In this case, authorization happens twice; once for authorizing `/endpoint` and once for forwarding to Thymeleaf to render the "endpoint" template.
 
- For that reason, you may want to <<match-by-dispatcher-type, permit all `FORWARD` dispatches>>.
 
- Another example of this principle is {spring-boot-reference-url}web.html#web.servlet.spring-mvc.error-handling[how Spring Boot handles errors].
 
- If the container catches an exception, say like the following:
 
- .Sample Erroring Spring MVC Controller
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- @Controller
 
- public class MyController {
 
-     @GetMapping("/endpoint")
 
-     public String endpoint() {
 
-         throw new UnsupportedOperationException("unsupported");
 
-     }
 
- }
 
- ----
 
- Kotlin::
 
- +
 
- [source,kotlin,role="secondary"]
 
- ----
 
- @Controller
 
- class MyController {
 
-     @GetMapping("/endpoint")
 
-     fun endpoint(): String {
 
-         throw UnsupportedOperationException("unsupported")
 
-     }
 
- }
 
- ----
 
- ======
 
- then Boot will dispatch it to the `ERROR` dispatch.
 
- In that case, authorization also happens twice; once for authorizing `/endpoint` and once for dispatching the error.
 
- For that reason, you may want to <<match-by-dispatcher-type, permit all `ERROR` dispatches>>.
 
- === `Authentication` Lookup is Deferred
 
- Remember that xref:servlet/authorization/architecture.adoc#_the_authorizationmanager[the `AuthorizationManager` API uses a `Supplier<Authentication>`].
 
- This matters with `authorizeHttpRequests` when requests are <<authorize-requests,always permitted or always denied>>.
 
- In those cases, xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[the `Authentication`] is not queried, making for a faster request.
 
- [[authorizing-endpoints]]
 
- == Authorizing an Endpoint
 
- You can configure Spring Security to have different rules by adding more rules in order of precedence.
 
- If you want to require that `/endpoint` only be accessible by end users with the `USER` authority, then you can do:
 
- .Authorize an Endpoint
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- @Bean
 
- SecurityFilterChain web(HttpSecurity http) throws Exception {
 
- 	http
 
- 		.authorizeHttpRequests((authorize) -> authorize
 
- 			.requestMatchers("/endpoint").hasAuthority('USER')
 
- 			.anyRequest().authenticated()
 
- 		)
 
-         // ...
 
- 	return http.build();
 
- }
 
- ----
 
- Kotlin::
 
- +
 
- [source,kotlin,role="secondary"]
 
- ----
 
- @Bean
 
- SecurityFilterChain web(HttpSecurity http) throws Exception {
 
- 	http {
 
-         authorizeHttpRequests {
 
-             authorize("/endpoint", hasAuthority('USER'))
 
-             authorize(anyRequest, authenticated)
 
-         }
 
- 	}
 
- 	return http.build();
 
- }
 
- ----
 
- Xml::
 
- +
 
- [source,xml,role="secondary"]
 
- ----
 
- <http>
 
-     <intercept-url pattern="/endpoint" access="hasAuthority('USER')"/>
 
-     <intercept-url pattern="/**" access="authenticated"/>
 
- </http>
 
- ----
 
- ======
 
- As you can see, the declaration can be broken up in to pattern/rule pairs.
 
- `AuthorizationFilter` processes these pairs in the order listed, applying only the first match to the request.
 
- This means that even though `/**` would also match for `/endpoint` the above rules are not a problem.
 
- The way to read the above rules is "if the request is `/endpoint`, then require the `USER` authority; else, only require authentication".
 
- Spring Security supports several patterns and several rules; you can also programmatically create your own of each.
 
- Once authorized, you can test it using xref:servlet/test/method.adoc#test-method-withmockuser[Security's test support] in the following way:
 
- .Test Endpoint Authorization
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- @WithMockUser(authorities="USER")
 
- @Test
 
- void endpointWhenUserAuthorityThenAuthorized() {
 
-     this.mvc.perform(get("/endpoint"))
 
-         .andExpect(status().isOk());
 
- }
 
- @WithMockUser
 
- @Test
 
- void endpointWhenNotUserAuthorityThenForbidden() {
 
-     this.mvc.perform(get("/endpoint"))
 
-         .andExpect(status().isForbidden());
 
- }
 
- @Test
 
- void anyWhenUnauthenticatedThenUnauthorized() {
 
-     this.mvc.perform(get("/any"))
 
-         .andExpect(status().isUnauthorized())
 
- }
 
- ----
 
- ======
 
- [[match-requests]]
 
- == Matching Requests
 
- Above you've already seen <<authorizing-endpoints, two ways to match requests>>.
 
- The first you saw was the simplest, which is to match any request.
 
- The second is to match by a URI pattern.
 
- Spring Security supports two languages for URI pattern-matching: <<match-by-ant,Ant>> (as seen above) and <<match-by-regex,Regular Expressions>>.
 
- [[match-by-ant]]
 
- === Matching Using Ant
 
- Ant is the default language that Spring Security uses to match requests.
 
- You can use it to match a single endpoint or a directory, and you can even capture placeholders for later use.
 
- You can also refine it to match a specific set of HTTP methods.
 
- Let's say that you instead of wanting to match the `/endpoint` endpoint, you want to match all endpoints under the `/resource` directory.
 
- In that case, you can do something like the following:
 
- .Match with Ant
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- http
 
-     .authorizeHttpRequests((authorize) -> authorize
 
-         .requestMatchers("/resource/**").hasAuthority("USER")
 
-         .anyRequest().authenticated()
 
-     )
 
- ----
 
- Kotlin::
 
- +
 
- [source,kotlin,role="secondary"]
 
- ----
 
- http {
 
-     authorizeHttpRequests {
 
-         authorize("/resource/**", hasAuthority("USER"))
 
-         authorize(anyRequest, authenticated)
 
-     }
 
- }
 
- ----
 
- Xml::
 
- +
 
- [source,xml,role="secondary"]
 
- ----
 
- <http>
 
-     <intercept-url pattern="/resource/**" access="hasAuthority('USER')"/>
 
-     <intercept-url pattern="/**" access="authenticated"/>
 
- </http>
 
- ----
 
- ======
 
- The way to read this is "if the request is `/resource` or some subdirectory, require the `USER` authority; otherwise, only require authentication"
 
- You can also extract path values from the request, as seen below:
 
- .Authorize and Extract
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- http
 
-     .authorizeHttpRequests((authorize) -> authorize
 
-         .requestMatchers("/resource/{name}").access(new WebExpressionAuthorizationManager("#name == authentication.name"))
 
-         .anyRequest().authenticated()
 
-     )
 
- ----
 
- Kotlin::
 
- +
 
- [source,kotlin,role="secondary"]
 
- ----
 
- http {
 
-     authorizeHttpRequests {
 
-         authorize("/resource/{name}", WebExpressionAuthorizationManager("#name == authentication.name"))
 
-         authorize(anyRequest, authenticated)
 
-     }
 
- }
 
- ----
 
- Xml::
 
- +
 
- [source,xml,role="secondary"]
 
- ----
 
- <http>
 
-     <intercept-url pattern="/resource/{name}" access="#name == authentication.name"/>
 
-     <intercept-url pattern="/**" access="authenticated"/>
 
- </http>
 
- ----
 
- ======
 
- Once authorized, you can test it using xref:servlet/test/method.adoc#test-method-withmockuser[Security's test support] in the following way:
 
- .Test Directory Authorization
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- @WithMockUser(authorities="USER")
 
- @Test
 
- void endpointWhenUserAuthorityThenAuthorized() {
 
-     this.mvc.perform(get("/endpoint/jon"))
 
-         .andExpect(status().isOk());
 
- }
 
- @WithMockUser
 
- @Test
 
- void endpointWhenNotUserAuthorityThenForbidden() {
 
-     this.mvc.perform(get("/endpoint/jon"))
 
-         .andExpect(status().isForbidden());
 
- }
 
- @Test
 
- void anyWhenUnauthenticatedThenUnauthorized() {
 
-     this.mvc.perform(get("/any"))
 
-         .andExpect(status().isUnauthorized())
 
- }
 
- ----
 
- ======
 
- [NOTE]
 
- Spring Security only matches paths.
 
- If you want to match query parameters, you will need a custom request matcher.
 
- [[match-by-regex]]
 
- === Matching Using Regular Expressions
 
- Spring Security supports matching requests against a regular expression.
 
- This can come in handy if you want to apply more strict matching criteria than `**` on a subdirectory.
 
- For example, consider a path that contains the username and the rule that all usernames must be alphanumeric.
 
- You can use {security-api-url}org/springframework/security/web/util/matcher/RegexRequestMatcher.html[`RegexRequestMatcher`] to respect this rule, like so:
 
- .Match with Regex
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- http
 
-     .authorizeHttpRequests((authorize) -> authorize
 
-         .requestMatchers(RegexRequestMatcher.regexMatcher("/resource/[A-Za-z0-9]+")).hasAuthority("USER")
 
-         .anyRequest().denyAll()
 
-     )
 
- ----
 
- Kotlin::
 
- +
 
- [source,kotlin,role="secondary"]
 
- ----
 
- http {
 
-     authorizeHttpRequests {
 
-         authorize(RegexRequestMatcher.regexMatcher("/resource/[A-Za-z0-9]+"), hasAuthority("USER"))
 
-         authorize(anyRequest, denyAll)
 
-     }
 
- }
 
- ----
 
- Xml::
 
- +
 
- [source,xml,role="secondary"]
 
- ----
 
- <http>
 
-     <intercept-url request-matcher="regex" pattern="/resource/[A-Za-z0-9]+" access="hasAuthority('USER')"/>
 
-     <intercept-url pattern="/**" access="denyAll"/>
 
- </http>
 
- ----
 
- ======
 
- [[match-by-httpmethod]]
 
- === Matching By Http Method
 
- You can also match rules by HTTP method.
 
- One place where this is handy is when authorizing by permissions granted, like being granted a `read` or `write` privilege.
 
- To require all ``GET``s to have the `read` permission and all ``POST``s to have the `write` permission, you can do something like this:
 
- .Match by HTTP Method
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- http
 
-     .authorizeHttpRequests((authorize) -> authorize
 
-         .requestMatchers(HttpMethod.GET).hasAuthority("read")
 
-         .requestMatchers(HttpMethod.POST).hasAuthority("write")
 
-         .anyRequest().denyAll()
 
-     )
 
- ----
 
- Kotlin::
 
- +
 
- [source,kotlin,role="secondary"]
 
- ----
 
- http {
 
-     authorizeHttpRequests {
 
-         authorize(HttpMethod.GET, hasAuthority("read"))
 
-         authorize(HttpMethod.POST, hasAuthority("write"))
 
-         authorize(anyRequest, denyAll)
 
-     }
 
- }
 
- ----
 
- Xml::
 
- +
 
- [source,xml,role="secondary"]
 
- ----
 
- <http>
 
-     <intercept-url http-method="GET" pattern="/**" access="hasAuthority('read')"/>
 
-     <intercept-url http-method="POST" pattern="/**" access="hasAuthority('write')"/>
 
-     <intercept-url pattern="/**" access="denyAll"/>
 
- </http>
 
- ----
 
- ======
 
- These authorization rules should read as: "if the request is a GET, then require `read` permission; else, if the request is a POST, then require `write` permission; else, deny the request"
 
- [TIP]
 
- Denying the request by default is a healthy security practice since it turns the set of rules into an allow list.
 
- Once authorized, you can test it using xref:servlet/test/method.adoc#test-method-withmockuser[Security's test support] in the following way:
 
- .Test Http Method Authorization
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- @WithMockUser(authorities="read")
 
- @Test
 
- void getWhenReadAuthorityThenAuthorized() {
 
-     this.mvc.perform(get("/any"))
 
-         .andExpect(status().isOk());
 
- }
 
- @WithMockUser
 
- @Test
 
- void getWhenNoReadAuthorityThenForbidden() {
 
-     this.mvc.perform(get("/any"))
 
-         .andExpect(status().isForbidden());
 
- }
 
- @WithMockUser(authorities="write")
 
- @Test
 
- void postWhenWriteAuthorityThenAuthorized() {
 
-     this.mvc.perform(post("/any").with(csrf()))
 
-         .andExpect(status().isOk())
 
- }
 
- @WithMockUser(authorities="read")
 
- @Test
 
- void postWhenNoWriteAuthorityThenForbidden() {
 
-     this.mvc.perform(get("/any").with(csrf()))
 
-         .andExpect(status().isForbidden());
 
- }
 
- ----
 
- ======
 
- [[match-by-dispatcher-type]]
 
- === Matching By Dispatcher Type
 
- [NOTE]
 
- This feature is not currently supported in XML
 
- As stated earlier, Spring Security <<_all_dispatches_are_authorized, authorizes all dispatcher types by default>>.
 
- And even though xref:servlet/authentication/architecture.adoc#servlet-authentication-securitycontext[the security context] established on the `REQUEST` dispatch carries over to subsequent dispatches, subtle mismatches can sometimes cause an unexpected `AccessDeniedException`.
 
- To address that, you can configure Spring Security Java configuration to allow dispatcher types like `FORWARD` and `ERROR`, like so:
 
- .Match by Dispatcher Type
 
- ====
 
- .Java
 
- [source,java,role="secondary"]
 
- ----
 
- http
 
-     .authorizeHttpRequests((authorize) -> authorize
 
-         .dispatcherTypeMatchers(DispatcherType.FORWARD, DispatcherType.ERROR).permitAll()
 
-         .requestMatchers("/endpoint").permitAll()
 
-         .anyRequest().denyAll()
 
-     )
 
- ----
 
- .Kotlin
 
- [source,kotlin,role="secondary"]
 
- ----
 
- http {
 
-     authorizeHttpRequests {
 
-         authorize(DispatcherTypeRequestMatcher(DispatcherType.FORWARD), permitAll)
 
-         authorize(DispatcherTypeRequestMatcher(DispatcherType.ERROR), permitAll)
 
-         authorize("/endpoint", permitAll)
 
-         authorize(anyRequest, denyAll)
 
-     }
 
- }
 
- ----
 
- ====
 
- [[match-by-mvc]]
 
- === Using an MvcRequestMatcher
 
- Generally speaking, you can use `requestMatchers(String)` as demonstrated above.
 
- However, if you map Spring MVC to a different servlet path, then you need to account for that in your security configuration.
 
- For example, if Spring MVC is mapped to `/spring-mvc` instead of `/` (the default), then you may have an endpoint like `/spring-mvc/my/controller` that you want to authorize.
 
- You need to use `MvcRequestMatcher` to split the servlet path and the controller path in your configuration like so:
 
- .Match by MvcRequestMatcher
 
- ====
 
- .Java
 
- [source,java,role="primary"]
 
- ----
 
- @Bean
 
- MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
 
- 	return new MvcRequestMatcher.Builder(introspector).servletPath("/spring-mvc");
 
- }
 
- @Bean
 
- SecurityFilterChain appEndpoints(HttpSecurity http, MvcRequestMatcher.Builder mvc) {
 
- 	http
 
-         .authorizeHttpRequests((authorize) -> authorize
 
-             .requestMatchers(mvc.pattern("/my/controller/**")).hasAuthority("controller")
 
-             .anyRequest().authenticated()
 
-         );
 
- 	return http.build();
 
- }
 
- ----
 
- .Kotlin
 
- [source,kotlin,role="secondary"]
 
- ----
 
- @Bean
 
- fun mvc(introspector: HandlerMappingIntrospector): MvcRequestMatcher.Builder =
 
-     MvcRequestMatcher.Builder(introspector).servletPath("/spring-mvc");
 
- @Bean
 
- fun appEndpoints(http: HttpSecurity, mvc: MvcRequestMatcher.Builder): SecurityFilterChain =
 
-     http {
 
-         authorizeHttpRequests {
 
-             authorize(mvc.pattern("/my/controller/**"), hasAuthority("controller"))
 
-             authorize(anyRequest, authenticated)
 
-         }
 
-     }
 
- ----
 
- .Xml
 
- [source,xml,role="secondary"]
 
- ----
 
- <http>
 
-     <intercept-url servlet-path="/spring-mvc" pattern="/my/controller/**" access="hasAuthority('controller')"/>
 
-     <intercept-url pattern="/**" access="authenticated"/>
 
- </http>
 
- ----
 
- ====
 
- This need can arise in at least two different ways:
 
- * If you use the `spring.mvc.servlet.path` Boot property to change the default path (`/`) to something else
 
- * If you register more than one Spring MVC `DispatcherServlet` (thus requiring that one of them not be the default path)
 
- [[match-by-custom]]
 
- === Using a Custom Matcher
 
- [NOTE]
 
- This feature is not currently supported in XML
 
- In Java configuration, you can create your own {security-api-url}org/springframework/security/web/util/matcher/RequestMatcher.html[`RequestMatcher`] and supply it to the DSL like so:
 
- .Authorize by Dispatcher Type
 
- ====
 
- .Java
 
- [source,java,role="secondary"]
 
- ----
 
- RequestMatcher printview = (request) -> request.getParameter("print") != null;
 
- http
 
-     .authorizeHttpRequests((authorize) -> authorize
 
-         .requestMatchers(printview).hasAuthority("print")
 
-         .anyRequest().authenticated()
 
-     )
 
- ----
 
- .Kotlin
 
- [source,kotlin,role="secondary"]
 
- ----
 
- val printview: RequestMatcher = { (request) -> request.getParameter("print") != null }
 
- http {
 
-     authorizeHttpRequests {
 
-         authorize(printview, hasAuthority("print"))
 
-         authorize(anyRequest, authenticated)
 
-     }
 
- }
 
- ----
 
- ====
 
- [TIP]
 
- Because {security-api-url}org/springframework/security/web/util/matcher/RequestMatcher.html[`RequestMatcher`] is a functional interface, you can supply it as a lambda in the DSL.
 
- However, if you want to extract values from the request, you will need to have a concrete class since that requires overriding a `default` method.
 
- Once authorized, you can test it using xref:servlet/test/method.adoc#test-method-withmockuser[Security's test support] in the following way:
 
- .Test Custom Authorization
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- @WithMockUser(authorities="print")
 
- @Test
 
- void printWhenPrintAuthorityThenAuthorized() {
 
-     this.mvc.perform(get("/any?print"))
 
-         .andExpect(status().isOk());
 
- }
 
- @WithMockUser
 
- @Test
 
- void printWhenNoPrintAuthorityThenForbidden() {
 
-     this.mvc.perform(get("/any?print"))
 
-         .andExpect(status().isForbidden());
 
- }
 
- ----
 
- ======
 
- [[authorize-requests]]
 
- == Authorizing Requests
 
- Once a request is matched, you can authorize it in several ways <<match-requests, already seen>> like `permitAll`, `denyAll`, and `hasAuthority`.
 
- As a quick summary, here are the authorization rules built into the DSL:
 
- * `permitAll` - The request requires no authorization and is a public endpoint; note that in this case, xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[the `Authentication`] is never retrieved from the session
 
- * `denyAll` - The request is not allowed under any circumstances; note that in this case, the `Authentication` is never retrieved from the session
 
- * `hasAuthority` - The request requires that the `Authentication` have xref:servlet/authorization/architecture.adoc#authz-authorities[a `GrantedAuthority`] that matches the given value
 
- * `hasRole` - A shortcut for `hasAuthority` that prefixes `ROLE_` or whatever is configured as the default prefix
 
- * `hasAnyAuthority` - The request requires that the `Authentication` have a `GrantedAuthority` that matches any of the given values
 
- * `hasAnyRole` - A shortcut for `hasAnyAuthority` that prefixes `ROLE_` or whatever is configured as the default prefix
 
- * `access` - The request uses this custom `AuthorizationManager` to determine access
 
- Having now learned the patterns, rules, and how they can be paired together, you should be able to understand what is going on in this more complex example:
 
- .Authorize Requests
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- import static jakarta.servlet.DispatcherType.*;
 
- import static org.springframework.security.authorization.AuthorizationManagers.allOf;
 
- import static org.springframework.security.authorization.AuthorityAuthorizationManager.hasAuthority;
 
- import static org.springframework.security.authorization.AuthorityAuthorizationManager.hasRole;
 
- @Bean
 
- SecurityFilterChain web(HttpSecurity http) throws Exception {
 
- 	http
 
- 		// ...
 
- 		.authorizeHttpRequests(authorize -> authorize                                  // <1>
 
-             .dispatcherTypeMatchers(FORWARD, ERROR).permitAll() // <2>
 
- 			.requestMatchers("/static/**", "/signup", "/about").permitAll()         // <3>
 
- 			.requestMatchers("/admin/**").hasRole("ADMIN")                             // <4>
 
- 			.requestMatchers("/db/**").access(allOf(hasAuthority('db'), hasRole('ADMIN')))   // <5>
 
- 			.anyRequest().denyAll()                                                // <6>
 
- 		);
 
- 	return http.build();
 
- }
 
- ----
 
- ======
 
- <1> There are multiple authorization rules specified.
 
- Each rule is considered in the order they were declared.
 
- <2> Dispatches `FORWARD` and `ERROR` are permitted to allow {spring-framework-reference-url}web.html#spring-web[Spring MVC] to render views and Spring Boot to render errors
 
- <3> 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".
 
- <4> 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.
 
- <5> Any URL that starts with "/db/" requires the user to have both been granted the "db" permission as well as be a "ROLE_ADMIN".
 
- You will notice that since we are using the `hasRole` expression we do not need to specify the "ROLE_" prefix.
 
- <6> 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.
 
- [[authorization-expressions]]
 
- == Expressing Authorization with SpEL
 
- While using a concrete `AuthorizationManager` is recommended, there are some cases where an expression is necessary, like with `<intercept-url>` or with JSP Taglibs.
 
- For that reason, this section will focus on examples from those domains.
 
- Given that, let's cover Spring Security's Web Security Authorization SpEL API a bit more in depth.
 
- Spring Security encapsulates all of its authorization fields and methods in a set of root objects.
 
- The most generic root object is called `SecurityExpressionRoot` and it forms the basis for `WebSecurityExpressionRoot`.
 
- Spring Security supplies this root object to `StandardEvaluationContext` when preparing to evaluate an authorization expression.
 
- [[using-authorization-expression-fields-and-methods]]
 
- === Using Authorization Expression Fields and Methods
 
- The first thing this provides is an enhanced set of authorization fields and methods to your SpEL expressions.
 
- What follows is a quick overview of the most common methods:
 
- * `permitAll` - The request requires no authorization to be invoked; note that in this case, xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[the `Authentication`] is never retrieved from the session
 
- * `denyAll` - The request is not allowed under any circumstances; note that in this case, the `Authentication` is never retrieved from the session
 
- * `hasAuthority` - The request requires that the `Authentication` have xref:servlet/authorization/architecture.adoc#authz-authorities[a `GrantedAuthority`] that matches the given value
 
- * `hasRole` - A shortcut for `hasAuthority` that prefixes `ROLE_` or whatever is configured as the default prefix
 
- * `hasAnyAuthority` - The request requires that the `Authentication` have a `GrantedAuthority` that matches any of the given values
 
- * `hasAnyRole` - A shortcut for `hasAnyAuthority` that prefixes `ROLE_` or whatever is configured as the default prefix
 
- * `hasPermission` - A hook into your `PermissionEvaluator` instance for doing object-level authorization
 
- And here is a brief look at the most common fields:
 
- * `authentication` - The `Authentication` instance associated with this method invocation
 
- * `principal` - The `Authentication#getPrincipal` associated with this method invocation
 
- Having now learned the patterns, rules, and how they can be paired together, you should be able to understand what is going on in this more complex example:
 
- .Authorize Requests Using SpEL
 
- [tabs]
 
- ======
 
- Xml::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- <http>
 
-     <intercept-url pattern="/static/**" access="permitAll"/> <1>
 
-     <intercept-url pattern="/admin/**" access="hasRole('ADMIN')"/> <2>
 
-     <intercept-url pattern="/db/**" access="hasAuthority('db') and hasRole('ADMIN')"/> <3>
 
-     <intercept-url pattern="/**" access="denyAll"/> <4>
 
- </http>
 
- ----
 
- ======
 
- <1> We specified a URL patters that any user can access.
 
- Specifically, any user can access a request if the URL starts with "/static/".
 
- <2> 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.
 
- <3> Any URL that starts with "/db/" requires the user to have both been granted the "db" permission as well as be a "ROLE_ADMIN".
 
- You will notice that since we are using the `hasRole` expression we do not need to specify the "ROLE_" prefix.
 
- <4> 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.
 
- [[using_path_parameters]]
 
- === Using Path Parameters
 
- Additionally, Spring Security provides a mechanism for discovering path parameters so they can also be accessed in the SpEL expression as well.
 
- For example, you can access a path parameter in your SpEL expression in the following way:
 
- .Authorize Request using SpEL path variable
 
- [tabs]
 
- ======
 
- Xml::
 
- +
 
- [source,xml,role="primary"]
 
- ----
 
- <http>
 
-     <intercept-url pattern="/resource/{name}" access="#name == authentication.name"/>
 
-     <intercept-url pattern="/**" access="authenticated"/>
 
- </http>
 
- ----
 
- ======
 
- This expression refers to the path variable after `/resource/` and requires that it is equal to `Authentication#getName`.
 
- [[remote-authorization-manager]]
 
- === Use an Authorization Database, Policy Agent, or Other Service
 
- If you want to configure Spring Security to use a separate service for authorization, you can create your own `AuthorizationManager` and match it to `anyRequest`.
 
- First, your `AuthorizationManager` may look something like this:
 
- .Open Policy Agent Authorization Manager
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- @Component
 
- public final class OpenPolicyAgentAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
 
-     @Override
 
-     public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext context) {
 
-         // make request to Open Policy Agent
 
-     }
 
- }
 
- ----
 
- ======
 
- Then, you can wire it into Spring Security in the following way:
 
- .Any Request Goes to Remote Service
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- @Bean
 
- SecurityFilterChain web(HttpSecurity http, AuthorizationManager<RequestAuthorizationContext> authz) throws Exception {
 
- 	http
 
- 		// ...
 
- 		.authorizeHttpRequests((authorize) -> authorize
 
-             .anyRequest().access(authz)
 
- 		);
 
- 	return http.build();
 
- }
 
- ----
 
- ======
 
- [[favor-permitall]]
 
- === Favor `permitAll` over `ignoring`
 
- When you have static resources it can be tempting to configure the filter chain to ignore these values.
 
- A more secure approach is to permit them using `permitAll` like so:
 
- .Permit Static Resources
 
- ====
 
- .Java
 
- [source,java,role="secondary"]
 
- ----
 
- http
 
-     .authorizeHttpRequests((authorize) -> authorize
 
-         .requestMatchers("/css/**").permitAll()
 
-         .anyRequest().authenticated()
 
-     )
 
- ----
 
- .Kotlin
 
- [source,kotlin,role="secondary"]
 
- ----
 
- http {
 
-     authorizeHttpRequests {
 
-         authorize("/css/**", permitAll)
 
-         authorize(anyRequest, authenticated)
 
-     }
 
- }
 
- ----
 
- ====
 
- It's more secure because even with static resources it's important to write secure headers, which Spring Security cannot do if the request is ignored.
 
- In this past, this came with a performance tradeoff since the session was consulted by Spring Security on every request.
 
- As of Spring Security 6, however, the session is no longer pinged unless required by the authorization rule.
 
- Because the performance impact is now addressed, Spring Security recommends using at least `permitAll` for all requests.
 
- [[migrate-authorize-requests]]
 
- == Migrating from `authorizeRequests`
 
- [NOTE]
 
- `AuthorizationFilter` supersedes {security-api-url}org/springframework/security/web/access/intercept/FilterSecurityInterceptor.html[`FilterSecurityInterceptor`].
 
- To remain backward compatible, `FilterSecurityInterceptor` remains the default.
 
- This section discusses how `AuthorizationFilter` works and how to override the default configuration.
 
- The {security-api-url}org/springframework/security/web/access/intercept/AuthorizationFilter.html[`AuthorizationFilter`] provides xref:servlet/authorization/index.adoc#servlet-authorization[authorization] for ``HttpServletRequest``s.
 
- 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].
 
- You can override the default when you declare a `SecurityFilterChain`.
 
- Instead of using {security-api-url}org/springframework/security/config/annotation/web/builders/HttpSecurity.html#authorizeRequests()[`authorizeRequests`], use `authorizeHttpRequests`, like so:
 
- .Use authorizeHttpRequests
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- @Bean
 
- SecurityFilterChain web(HttpSecurity http) throws AuthenticationException {
 
-     http
 
-         .authorizeHttpRequests((authorize) -> authorize
 
-             .anyRequest().authenticated();
 
-         )
 
-         // ...
 
-     return http.build();
 
- }
 
- ----
 
- ======
 
- This improves on `authorizeRequests` in a number of ways:
 
- 1. Uses the simplified `AuthorizationManager` API instead of metadata sources, config attributes, decision managers, and voters.
 
- This simplifies reuse and customization.
 
- 2. Delays `Authentication` lookup.
 
- Instead of the authentication needing to be looked up for every request, it will only look it up in requests where an authorization decision requires authentication.
 
- 3. Bean-based configuration support.
 
- When `authorizeHttpRequests` is used instead of `authorizeRequests`, then {security-api-url}org/springframework/security/web/access/intercept/AuthorizationFilter.html[`AuthorizationFilter`] is used instead of {security-api-url}org/springframework/security/web/access/intercept/FilterSecurityInterceptor.html[`FilterSecurityInterceptor`].
 
- === Migrating Expressions
 
- Where possible, it is recommended that you use type-safe authorization managers instead of SpEL.
 
- For Java configuration, {security-api-url}org/springframework/security/web/access/expression/WebExpressionAuthorizationManager.html[`WebExpressionAuthorizationManager`] is available to help migrate legacy SpEL.
 
- To use `WebExpressionAuthorizationManager`, you can construct one with the expression you are trying to migrate, like so:
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- .requestMatchers("/test/**").access(new WebExpressionAuthorizationManager("hasRole('ADMIN') && hasRole('USER')"))
 
- ----
 
- Kotlin::
 
- +
 
- [source,kotlin,role="secondary"]
 
- ----
 
- .requestMatchers("/test/**").access(WebExpressionAuthorizationManager("hasRole('ADMIN') && hasRole('USER')"))
 
- ----
 
- ======
 
- If you are referring to a bean in your expression like so: `@webSecurity.check(authentication, request)`, it's recommended that you instead call the bean directly, which will look something like the following:
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- .requestMatchers("/test/**").access((authentication, context) ->
 
-     new AuthorizationDecision(webSecurity.check(authentication.get(), context.getRequest())))
 
- ----
 
- Kotlin::
 
- +
 
- [source,kotlin,role="secondary"]
 
- ----
 
- .requestMatchers("/test/**").access((authentication, context): AuthorizationManager<RequestAuthorizationContext> ->
 
-     AuthorizationDecision(webSecurity.check(authentication.get(), context.getRequest())))
 
- ----
 
- ======
 
- For complex instructions that include bean references as well as other expressions, it is recommended that you change those to implement `AuthorizationManager` and refer to them by calling `.access(AuthorizationManager)`.
 
- If you are not able to do that, you can configure a {security-api-url}org/springframework/security/web/access/expression/DefaultHttpSecurityExpressionHandler.html[`DefaultHttpSecurityExpressionHandler`] with a bean resolver and supply that to `WebExpressionAuthorizationManager#setExpressionhandler`.
 
- [[security-matchers]]
 
- == Security Matchers
 
- The {security-api-url}org/springframework/security/web/util/matcher/RequestMatcher.html[`RequestMatcher`] interface is used to determine if a request matches a given rule.
 
- We use `securityMatchers` to determine if xref:servlet/configuration/java.adoc#jc-httpsecurity[a given `HttpSecurity`] should be applied to a given request.
 
- The same way, we can use `requestMatchers` to determine the authorization rules that we should apply to a given request.
 
- Look at the following example:
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- @Configuration
 
- @EnableWebSecurity
 
- public class SecurityConfig {
 
- 	@Bean
 
- 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 
- 		http
 
- 			.securityMatcher("/api/**")                            <1>
 
- 			.authorizeHttpRequests(authorize -> authorize
 
- 				.requestMatchers("/user/**").hasRole("USER")       <2>
 
- 				.requestMatchers("/admin/**").hasRole("ADMIN")     <3>
 
- 				.anyRequest().authenticated()                      <4>
 
- 			)
 
- 			.formLogin(withDefaults());
 
- 		return http.build();
 
- 	}
 
- }
 
- ----
 
- Kotlin::
 
- +
 
- [source,kotlin,role="secondary"]
 
- ----
 
- @Configuration
 
- @EnableWebSecurity
 
- open class SecurityConfig {
 
-     @Bean
 
-     open fun web(http: HttpSecurity): SecurityFilterChain {
 
-         http {
 
-             securityMatcher("/api/**")                                           <1>
 
-             authorizeHttpRequests {
 
-                 authorize("/user/**", hasRole("USER"))                           <2>
 
-                 authorize("/admin/**", hasRole("ADMIN"))                         <3>
 
-                 authorize(anyRequest, authenticated)                             <4>
 
-             }
 
-         }
 
-         return http.build()
 
-     }
 
- }
 
- ----
 
- ======
 
- <1> Configure `HttpSecurity` to only be applied to URLs that start with `/api/`
 
- <2> Allow access to URLs that start with `/user/` to users with the `USER` role
 
- <3> Allow access to URLs that start with `/admin/` to users with the `ADMIN` role
 
- <4> Any other request that doesn't match the rules above, will require authentication
 
- The `securityMatcher(s)` and `requestMatcher(s)` methods will decide which `RequestMatcher` implementation fits best for your application: If {spring-framework-reference-url}web.html#spring-web[Spring MVC] is in the classpath, then {security-api-url}org/springframework/security/web/servlet/util/matcher/MvcRequestMatcher.html[`MvcRequestMatcher`] will be used, otherwise, {security-api-url}org/springframework/security/web/servlet/util/matcher/AntPathRequestMatcher.html[`AntPathRequestMatcher`] will be used.
 
- You can read more about the Spring MVC integration xref:servlet/integrations/mvc.adoc[here].
 
- If you want to use a specific `RequestMatcher`, just pass an implementation to the `securityMatcher` and/or `requestMatcher` methods:
 
- [tabs]
 
- ======
 
- Java::
 
- +
 
- [source,java,role="primary"]
 
- ----
 
- import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher; <1>
 
- import static org.springframework.security.web.util.matcher.RegexRequestMatcher.regexMatcher;
 
- @Configuration
 
- @EnableWebSecurity
 
- public class SecurityConfig {
 
- 	@Bean
 
- 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 
- 		http
 
- 			.securityMatcher(antMatcher("/api/**"))                              <2>
 
- 			.authorizeHttpRequests(authorize -> authorize
 
- 				.requestMatchers(antMatcher("/user/**")).hasRole("USER")         <3>
 
- 				.requestMatchers(regexMatcher("/admin/.*")).hasRole("ADMIN")     <4>
 
- 				.requestMatchers(new MyCustomRequestMatcher()).hasRole("SUPERVISOR")     <5>
 
- 				.anyRequest().authenticated()
 
- 			)
 
- 			.formLogin(withDefaults());
 
- 		return http.build();
 
- 	}
 
- }
 
- public class MyCustomRequestMatcher implements RequestMatcher {
 
-     @Override
 
-     public boolean matches(HttpServletRequest request) {
 
-         // ...
 
-     }
 
- }
 
- ----
 
- Kotlin::
 
- +
 
- [source,kotlin,role="secondary"]
 
- ----
 
- import org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher <1>
 
- import org.springframework.security.web.util.matcher.RegexRequestMatcher.regexMatcher
 
- @Configuration
 
- @EnableWebSecurity
 
- open class SecurityConfig {
 
-     @Bean
 
-     open fun web(http: HttpSecurity): SecurityFilterChain {
 
-         http {
 
-             securityMatcher(antMatcher("/api/**"))                               <2>
 
-             authorizeHttpRequests {
 
-                 authorize(antMatcher("/user/**"), hasRole("USER"))               <3>
 
-                 authorize(regexMatcher("/admin/**"), hasRole("ADMIN"))           <4>
 
-                 authorize(MyCustomRequestMatcher(), hasRole("SUPERVISOR"))       <5>
 
-                 authorize(anyRequest, authenticated)
 
-             }
 
-         }
 
-         return http.build()
 
-     }
 
- }
 
- ----
 
- ======
 
- <1> Import the static factory methods from `AntPathRequestMatcher` and `RegexRequestMatcher` to create `RequestMatcher` instances.
 
- <2> Configure `HttpSecurity` to only be applied to URLs that start with `/api/`, using `AntPathRequestMatcher`
 
- <3> Allow access to URLs that start with `/user/` to users with the `USER` role, using `AntPathRequestMatcher`
 
- <4> Allow access to URLs that start with `/admin/` to users with the `ADMIN` role, using `RegexRequestMatcher`
 
- <5> Allow access to URLs that match the `MyCustomRequestMatcher` to users with the `SUPERVISOR` role, using a custom `RequestMatcher`
 
- == Further Reading
 
- Now that you have secured your application's requests, consider xref:servlet/authorization/method-security.adoc[securing its methods].
 
- You can also read further on xref:servlet/test/index.adoc[testing your application] or on integrating Spring Security with other aspects of you application like xref:servlet/integrations/data.adoc[the data layer] or xref:servlet/integrations/observability.adoc[tracing and metrics].
 
 
  |