123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695 |
- [[jc]]
- = Java Configuration
- General support for {spring-framework-reference-url}core/beans/java.html[Java configuration] was added to Spring Framework in Spring 3.1.
- Spring Security 3.2 introduced Java configuration to let users configure Spring Security without the use of any XML.
- If you are familiar with the xref:servlet/configuration/xml-namespace.adoc#ns-config[Security Namespace Configuration], you should find quite a few similarities between it and Spring Security Java configuration.
- [NOTE]
- ====
- Spring Security provides https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration[lots of sample applications] to demonstrate the use of Spring Security Java Configuration.
- ====
- [[jc-hello-wsca]]
- == Hello Web Security Java Configuration
- The first step is to create our Spring Security Java Configuration.
- The configuration creates a Servlet Filter known as the `springSecurityFilterChain`, which is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the log in form, and so on) within your application.
- The following example shows the most basic example of a Spring Security Java Configuration:
- [source,java]
- ----
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.annotation.*;
- import org.springframework.security.config.annotation.authentication.builders.*;
- import org.springframework.security.config.annotation.web.configuration.*;
- @Configuration
- @EnableWebSecurity
- public class WebSecurityConfig {
- @Bean
- public UserDetailsService userDetailsService() {
- InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
- manager.createUser(User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build());
- return manager;
- }
- }
- ----
- This configuration is not complex or extensive, but it does a lot:
- * Require authentication to every URL in your application
- * Generate a login form for you
- * Let the user with a *Username* of `user` and a *Password* of `password` authenticate with form based authentication
- * Let the user logout
- * https://en.wikipedia.org/wiki/Cross-site_request_forgery[CSRF attack] prevention
- * https://en.wikipedia.org/wiki/Session_fixation[Session Fixation] protection
- * Security Header integration:
- ** https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security[HTTP Strict Transport Security] for secure requests
- ** https://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx[X-Content-Type-Options] integration
- ** Cache Control (which you can override later in your application to allow caching of your static resources)
- ** https://msdn.microsoft.com/en-us/library/dd565647(v=vs.85).aspx[X-XSS-Protection] integration
- ** X-Frame-Options integration to help prevent https://en.wikipedia.org/wiki/Clickjacking[Clickjacking]
- * Integration with the following Servlet API methods:
- ** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getRemoteUser()[`HttpServletRequest#getRemoteUser()`]
- ** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getUserPrincipal()[`HttpServletRequest#getUserPrincipal()`]
- ** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#isUserInRole(java.lang.String)[`HttpServletRequest#isUserInRole(java.lang.String)`]
- ** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#login(java.lang.String,%20java.lang.String)[`HttpServletRequest#login(java.lang.String, java.lang.String)`]
- ** https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#logout()[`HttpServletRequest#logout()`]
- === AbstractSecurityWebApplicationInitializer
- The next step is to register the `springSecurityFilterChain` with the WAR file.
- You can do so in Java configuration with {spring-framework-reference-url}web/webmvc/mvc-servlet/container-config.html[Spring's `WebApplicationInitializer` support] in a Servlet 3.0+ environment.
- Not surprisingly, Spring Security provides a base class (`AbstractSecurityWebApplicationInitializer`) to ensure that the `springSecurityFilterChain` gets registered for you.
- The way in which we use `AbstractSecurityWebApplicationInitializer` differs depending on if we are already using Spring or if Spring Security is the only Spring component in our application.
- * <<abstractsecuritywebapplicationinitializer-without-existing-spring>> - Use these instructions if you are not already using Spring
- * <<abstractsecuritywebapplicationinitializer-with-spring-mvc>> - Use these instructions if you are already using Spring
- [[abstractsecuritywebapplicationinitializer-without-existing-spring]]
- === AbstractSecurityWebApplicationInitializer without Existing Spring
- If you are not using Spring or Spring MVC, you need to pass the `WebSecurityConfig` to the superclass to ensure the configuration is picked up:
- [source,java]
- ----
- import org.springframework.security.web.context.*;
- public class SecurityWebApplicationInitializer
- extends AbstractSecurityWebApplicationInitializer {
- public SecurityWebApplicationInitializer() {
- super(WebSecurityConfig.class);
- }
- }
- ----
- The `SecurityWebApplicationInitializer`:
- * Automatically registers the `springSecurityFilterChain` Filter for every URL in your application.
- * Add a `ContextLoaderListener` that loads the <<jc-hello-wsca,WebSecurityConfig>>.
- [[abstractsecuritywebapplicationinitializer-with-spring-mvc]]
- === AbstractSecurityWebApplicationInitializer with Spring MVC
- If we use Spring elsewhere in our application, we probably already have a `WebApplicationInitializer` that is loading our Spring Configuration.
- If we use the previous configuration, we would get an error.
- Instead, we should register Spring Security with the existing `ApplicationContext`.
- For example, if we use Spring MVC, our `SecurityWebApplicationInitializer` could look something like the following:
- [source,java]
- ----
- import org.springframework.security.web.context.*;
- public class SecurityWebApplicationInitializer
- extends AbstractSecurityWebApplicationInitializer {
- }
- ----
- This only registers the `springSecurityFilterChain` for every URL in your application.
- After that, we need to ensure that `WebSecurityConfig` was loaded in our existing `ApplicationInitializer`.
- For example, if we use Spring MVC it is added in the `getServletConfigClasses()`:
- [[message-web-application-inititializer-java]]
- [source,java]
- ----
- public class MvcWebApplicationInitializer extends
- AbstractAnnotationConfigDispatcherServletInitializer {
- @Override
- protected Class<?>[] getServletConfigClasses() {
- return new Class[] { WebSecurityConfig.class, WebMvcConfig.class };
- }
- // ... other overrides ...
- }
- ----
- The reason for this is that Spring Security needs to be able to inspect some Spring MVC configuration in order to appropriately configure xref:servlet/authorization/authorize-http-requests.adoc#authorizing-endpoints[underlying request matchers], so they need to be in the same application context.
- Placing Spring Security in `getRootConfigClasses` places it into a parent application context that may not be able to find Spring MVC's `PathPatternParser`.
- ==== Configuring for Multiple Spring MVC Dispatchers
- If desired, any Spring Security configuration that is unrelated to Spring MVC may be placed in a different configuration class like so:
- [source,java]
- ----
- public class MvcWebApplicationInitializer extends
- AbstractAnnotationConfigDispatcherServletInitializer {
- @Override
- protected Class<?>[] getRootConfigClasses() {
- return new Class[] { NonWebSecurityConfig.class };
- }
- @Override
- protected Class<?>[] getServletConfigClasses() {
- return new Class[] { WebSecurityConfig.class, WebMvcConfig.class };
- }
- // ... other overrides ...
- }
- ----
- This can be helpful if you have multiple instances of `AbstractAnnotationConfigDispatcherServletInitializer` and don't want to duplicate the general security configuration across both of them.
- [[jc-httpsecurity]]
- == HttpSecurity
- Thus far, our <<jc-hello-wsca,`WebSecurityConfig`>> contains only information about how to authenticate our users.
- How does Spring Security know that we want to require all users to be authenticated?
- How does Spring Security know we want to support form-based authentication?
- Actually, there is a configuration class (called `SecurityFilterChain`) that is being invoked behind the scenes.
- It is configured with the following default implementation:
- [source,java]
- ----
- @Bean
- public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
- http
- .authorizeHttpRequests((authorize) -> authorize
- .anyRequest().authenticated()
- )
- .formLogin(Customizer.withDefaults())
- .httpBasic(Customizer.withDefaults());
- return http.build();
- }
- ----
- The default configuration (shown in the preceding example):
- * Ensures that any request to our application requires the user to be authenticated
- * Lets users authenticate with form-based login
- * Lets users authenticate with HTTP Basic authentication
- Note that this configuration parallels the XML namespace configuration:
- [source,xml]
- ----
- <http>
- <intercept-url pattern="/**" access="authenticated"/>
- <form-login />
- <http-basic />
- </http>
- ----
- === Multiple HttpSecurity Instances
- To effectively manage security in an application where certain areas need different protection, we can employ multiple filter chains alongside the `securityMatcher` DSL method.
- This approach allows us to define distinct security configurations tailored to specific parts of the application, enhancing overall application security and control.
- We can configure multiple `HttpSecurity` instances just as we can have multiple `<http>` blocks in XML.
- The key is to register multiple `SecurityFilterChain` ``@Bean``s.
- The following example has a different configuration for URLs that begin with `/api/`:
- [[multiple-httpsecurity-instances-java]]
- [source,java]
- ----
- @Configuration
- @EnableWebSecurity
- public class MultiHttpSecurityConfig {
- @Bean <1>
- public UserDetailsService userDetailsService() throws Exception {
- UserBuilder users = User.withDefaultPasswordEncoder();
- InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
- manager.createUser(users.username("user").password("password").roles("USER").build());
- manager.createUser(users.username("admin").password("password").roles("USER","ADMIN").build());
- return manager;
- }
- @Bean
- @Order(1) <2>
- public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
- http
- .securityMatcher("/api/**") <3>
- .authorizeHttpRequests((authorize) -> authorize
- .anyRequest().hasRole("ADMIN")
- )
- .httpBasic(Customizer.withDefaults());
- return http.build();
- }
- @Bean <4>
- public SecurityFilterChain formLoginFilterChain(HttpSecurity http) throws Exception {
- http
- .authorizeHttpRequests((authorize) -> authorize
- .anyRequest().authenticated()
- )
- .formLogin(Customizer.withDefaults());
- return http.build();
- }
- }
- ----
- <1> Configure Authentication as usual.
- <2> Create an instance of `SecurityFilterChain` that contains `@Order` to specify which `SecurityFilterChain` should be considered first.
- <3> The `http.securityMatcher()` states that this `HttpSecurity` is applicable only to URLs that begin with `/api/`.
- <4> Create another instance of `SecurityFilterChain`.
- If the URL does not begin with `/api/`, this configuration is used.
- This configuration is considered after `apiFilterChain`, since it has an `@Order` value after `1` (no `@Order` defaults to last).
- === Choosing `securityMatcher` or `requestMatchers`
- A common question is:
- > What is the difference between the `http.securityMatcher()` method and `requestMatchers()` used for request authorization (i.e. inside of `http.authorizeHttpRequests()`)?
- To answer this question, it helps to understand that each `HttpSecurity` instance used to build a `SecurityFilterChain` contains a `RequestMatcher` to match incoming requests.
- If a request does not match a `SecurityFilterChain` with higher priority (e.g. `@Order(1)`), the request can be tried against a filter chain with lower priority (e.g. no `@Order`).
- [NOTE]
- ====
- The matching logic for multiple filter chains is performed by the xref:servlet/architecture.adoc#servlet-filterchainproxy[`FilterChainProxy`].
- ====
- The default `RequestMatcher` matches *any request* to ensure Spring Security protects *all requests by default*.
- [NOTE]
- ====
- Specifying a `securityMatcher` overrides this default.
- ====
- [WARNING]
- ====
- If no filter chain matches a particular request, the request is *not protected* by Spring Security.
- ====
- The following example demonstrates a single filter chain that only protects requests that begin with `/secured/`:
- [[choosing-security-matcher-request-matchers-java]]
- [source,java]
- ----
- @Configuration
- @EnableWebSecurity
- public class PartialSecurityConfig {
- @Bean
- public UserDetailsService userDetailsService() throws Exception {
- // ...
- }
- @Bean
- public SecurityFilterChain securedFilterChain(HttpSecurity http) throws Exception {
- http
- .securityMatcher("/secured/**") <1>
- .authorizeHttpRequests((authorize) -> authorize
- .requestMatchers("/secured/user").hasRole("USER") <2>
- .requestMatchers("/secured/admin").hasRole("ADMIN") <3>
- .anyRequest().authenticated() <4>
- )
- .httpBasic(Customizer.withDefaults())
- .formLogin(Customizer.withDefaults());
- return http.build();
- }
- }
- ----
- <1> Requests that begin with `/secured/` will be protected but any other requests are not protected.
- <2> Requests to `/secured/user` require the `ROLE_USER` authority.
- <3> Requests to `/secured/admin` require the `ROLE_ADMIN` authority.
- <4> Any other requests (such as `/secured/other`) simply require an authenticated user.
- [TIP]
- ====
- It is _recommended_ to provide a `SecurityFilterChain` that does not specify any `securityMatcher` to ensure the entire application is protected, as demonstrated in the <<multiple-httpsecurity-instances-java,earlier example>>.
- ====
- Notice that the `requestMatchers` method only applies to individual authorization rules.
- Each request listed there must also match the overall `securityMatcher` for this particular `HttpSecurity` instance used to create the `SecurityFilterChain`.
- Using `anyRequest()` in this example matches all other requests within this particular `SecurityFilterChain` (which must begin with `/secured/`).
- [NOTE]
- ====
- See xref:servlet/authorization/authorize-http-requests.adoc[Authorize HttpServletRequests] for more information on `requestMatchers`.
- ====
- === `SecurityFilterChain` Endpoints
- Several filters in the `SecurityFilterChain` directly provide endpoints, such as the `UsernamePasswordAuthenticationFilter` which is set up by `http.formLogin()` and provides the `POST /login` endpoint.
- In the <<choosing-security-matcher-request-matchers-java,above example>>, the `/login` endpoint is not matched by `http.securityMatcher("/secured/**")` and therefore that application would not have any `GET /login` or `POST /login` endpoint.
- Such requests would return `404 Not Found`.
- This is often surprising to users.
- Specifying `http.securityMatcher()` affects what requests are matched by that `SecurityFilterChain`.
- However, it does not automatically affect endpoints provided by the filter chain.
- In such cases, you may need to customize the URL of any endpoints you would like the filter chain to provide.
- The following example demonstrates a configuration that secures requests that begin with `/secured/` and denies all other requests, while also customizing endpoints provided by the `SecurityFilterChain`:
- [[security-filter-chain-endpoints-java]]
- [source,java]
- ----
- @Configuration
- @EnableWebSecurity
- public class SecuredSecurityConfig {
- @Bean
- public UserDetailsService userDetailsService() throws Exception {
- // ...
- }
- @Bean
- @Order(1)
- public SecurityFilterChain securedFilterChain(HttpSecurity http) throws Exception {
- http
- .securityMatcher("/secured/**") <1>
- .authorizeHttpRequests((authorize) -> authorize
- .anyRequest().authenticated() <2>
- )
- .formLogin((formLogin) -> formLogin <3>
- .loginPage("/secured/login")
- .loginProcessingUrl("/secured/login")
- .permitAll()
- )
- .logout((logout) -> logout <4>
- .logoutUrl("/secured/logout")
- .logoutSuccessUrl("/secured/login?logout")
- .permitAll()
- )
- .formLogin(Customizer.withDefaults());
- return http.build();
- }
- @Bean
- public SecurityFilterChain defaultFilterChain(HttpSecurity http) throws Exception {
- http
- .authorizeHttpRequests((authorize) -> authorize
- .anyRequest().denyAll() <5>
- );
- return http.build();
- }
- }
- ----
- <1> Requests that begin with `/secured/` will be protected by this filter chain.
- <2> Requests that begin with `/secured/` require an authenticated user.
- <3> Customize form login to prefix URLs with `/secured/`.
- <4> Customize logout to prefix URLs with `/secured/`.
- <5> All other requests will be denied.
- [NOTE]
- ====
- This example customizes the login and logout pages, which disables Spring Security's generated pages.
- You must xref:servlet/authentication/passwords/form.adoc#servlet-authentication-form-custom[provide your own] custom endpoints for `GET /secured/login` and `GET /secured/logout`.
- Note that Spring Security still provides `POST /secured/login` and `POST /secured/logout` endpoints for you.
- ====
- === Real World Example
- The following example demonstrates a slightly more real-world configuration putting all of these elements together:
- [[real-world-example-java]]
- [source,java]
- ----
- @Configuration
- @EnableWebSecurity
- public class BankingSecurityConfig {
- @Bean <1>
- public UserDetailsService userDetailsService() {
- UserBuilder users = User.withDefaultPasswordEncoder();
- InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
- manager.createUser(users.username("user1").password("password").roles("USER", "VIEW_BALANCE").build());
- manager.createUser(users.username("user2").password("password").roles("USER").build());
- manager.createUser(users.username("admin").password("password").roles("ADMIN").build());
- return manager;
- }
- @Bean
- @Order(1) <2>
- public SecurityFilterChain approvalsSecurityFilterChain(HttpSecurity http) throws Exception {
- String[] approvalsPaths = { "/accounts/approvals/**", "/loans/approvals/**", "/credit-cards/approvals/**" };
- http
- .securityMatcher(approvalsPaths)
- .authorizeHttpRequests((authorize) -> authorize
- .anyRequest().hasRole("ADMIN")
- )
- .httpBasic(Customizer.withDefaults());
- return http.build();
- }
- @Bean
- @Order(2) <3>
- public SecurityFilterChain bankingSecurityFilterChain(HttpSecurity http) throws Exception {
- String[] bankingPaths = { "/accounts/**", "/loans/**", "/credit-cards/**", "/balances/**" };
- String[] viewBalancePaths = { "/balances/**" };
- http
- .securityMatcher(bankingPaths)
- .authorizeHttpRequests((authorize) -> authorize
- .requestMatchers(viewBalancePaths).hasRole("VIEW_BALANCE")
- .anyRequest().hasRole("USER")
- );
- return http.build();
- }
- @Bean <4>
- public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
- String[] allowedPaths = { "/", "/user-login", "/user-logout", "/notices", "/contact", "/register" };
- http
- .authorizeHttpRequests((authorize) -> authorize
- .requestMatchers(allowedPaths).permitAll()
- .anyRequest().authenticated()
- )
- .formLogin((formLogin) -> formLogin
- .loginPage("/user-login")
- .loginProcessingUrl("/user-login")
- )
- .logout((logout) -> logout
- .logoutUrl("/user-logout")
- .logoutSuccessUrl("/?logout")
- );
- return http.build();
- }
- }
- ----
- <1> Begin by configuring authentication settings.
- <2> Define a `SecurityFilterChain` instance with `@Order(1)`, which means that this filter chain will have the highest priority.
- This filter chain applies only to requests that begin with `/accounts/approvals/`, `/loans/approvals/` or `/credit-cards/approvals/`.
- Requests to this filter chain require the `ROLE_ADMIN` authority and allow HTTP Basic Authentication.
- <3> Next, create another `SecurityFilterChain` instance with `@Order(2)` which will be considered second.
- This filter chain applies only to requests that begin with `/accounts/`, `/loans/`, `/credit-cards/`, or `/balances/`.
- Notice that because this filter chain is second, any requests that include `/approvals/` will match the previous filter chain and will *not* be matched by this filter chain.
- Requests to this filter chain require the `ROLE_USER` authority.
- This filter chain does not define any authentication because the next (default) filter chain contains that configuration.
- <4> Lastly, create an additional `SecurityFilterChain` instance without an `@Order` annotation.
- This configuration will handle requests not covered by the other filter chains and will be processed last (no `@Order` defaults to last).
- Requests that match `/`, `/user-login`, `/user-logout`, `/notices`, `/contact` and `/register` allow access without authentication.
- Any other requests require the user to be authenticated to access any URL not explicitly allowed or protected by other filter chains.
- [[jc-custom-dsls]]
- == Custom DSLs
- You can provide your own custom DSLs in Spring Security:
- [tabs]
- ======
- Java::
- +
- [source,java,role="primary"]
- ----
- public class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurity> {
- private boolean flag;
- @Override
- public void init(HttpSecurity http) throws Exception {
- // any method that adds another configurer
- // must be done in the init method
- http.csrf().disable();
- }
- @Override
- public void configure(HttpSecurity http) throws Exception {
- ApplicationContext context = http.getSharedObject(ApplicationContext.class);
- // here we lookup from the ApplicationContext. You can also just create a new instance.
- MyFilter myFilter = context.getBean(MyFilter.class);
- myFilter.setFlag(flag);
- http.addFilterBefore(myFilter, UsernamePasswordAuthenticationFilter.class);
- }
- public MyCustomDsl flag(boolean value) {
- this.flag = value;
- return this;
- }
- public static MyCustomDsl customDsl() {
- return new MyCustomDsl();
- }
- }
- ----
- Kotlin::
- +
- [source,kotlin,role="secondary"]
- ----
- class MyCustomDsl : AbstractHttpConfigurer<MyCustomDsl, HttpSecurity>() {
- var flag: Boolean = false
- override fun init(http: HttpSecurity) {
- // any method that adds another configurer
- // must be done in the init method
- http.csrf().disable()
- }
- override fun configure(http: HttpSecurity) {
- val context: ApplicationContext = http.getSharedObject(ApplicationContext::class.java)
- // here we lookup from the ApplicationContext. You can also just create a new instance.
- val myFilter: MyFilter = context.getBean(MyFilter::class.java)
- myFilter.setFlag(flag)
- http.addFilterBefore(myFilter, UsernamePasswordAuthenticationFilter::class.java)
- }
- companion object {
- @JvmStatic
- fun customDsl(): MyCustomDsl {
- return MyCustomDsl()
- }
- }
- }
- ----
- ======
- [NOTE]
- ====
- This is actually how methods like `HttpSecurity.authorizeHttpRequests()` are implemented.
- ====
- You can then use the custom DSL:
- [tabs]
- ======
- Java::
- +
- [source,java,role="primary"]
- ----
- @Configuration
- @EnableWebSecurity
- public class Config {
- @Bean
- public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
- http
- .with(MyCustomDsl.customDsl(), (dsl) -> dsl
- .flag(true)
- )
- // ...
- return http.build();
- }
- }
- ----
- Kotlin::
- +
- [source,kotlin,role="secondary"]
- ----
- @Configuration
- @EnableWebSecurity
- class Config {
- @Bean
- fun filterChain(http: HttpSecurity): SecurityFilterChain {
- http
- .with(MyCustomDsl.customDsl()) {
- flag = true
- }
- // ...
- return http.build()
- }
- }
- ----
- ======
- The code is invoked in the following order:
- * Code in the `Config.filterChain` method is invoked
- * Code in the `MyCustomDsl.init` method is invoked
- * Code in the `MyCustomDsl.configure` method is invoked
- If you want, you can have `HttpSecurity` add `MyCustomDsl` by default by using `SpringFactories`.
- For example, you can create a resource on the classpath named `META-INF/spring.factories` with the following contents:
- .META-INF/spring.factories
- [source]
- ----
- org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer = sample.MyCustomDsl
- ----
- You can also explicit disable the default:
- [tabs]
- ======
- Java::
- +
- [source,java,role="primary"]
- ----
- @Configuration
- @EnableWebSecurity
- public class Config {
- @Bean
- public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
- http
- .with(MyCustomDsl.customDsl(), (dsl) -> dsl
- .disable()
- )
- ...;
- return http.build();
- }
- }
- ----
- Kotlin::
- +
- [source,kotlin,role="secondary"]
- ----
- @Configuration
- @EnableWebSecurity
- class Config {
- @Bean
- fun filterChain(http: HttpSecurity): SecurityFilterChain {
- http
- .with(MyCustomDsl.customDsl()) {
- disable()
- }
- // ...
- return http.build()
- }
- }
- ----
- ======
- [[post-processing-configured-objects]]
- == Post Processing Configured Objects
- Spring Security's Java configuration does not expose every property of every object that it configures.
- This simplifies the configuration for a majority of users.
- After all, if every property were exposed, users could use standard bean configuration.
- While there are good reasons to not directly expose every property, users may still need more advanced configuration options.
- To address this issue, Spring Security introduces the concept of an `ObjectPostProcessor`, which can be used to modify or replace many of the `Object` instances created by the Java Configuration.
- For example, to configure the `filterSecurityPublishAuthorizationSuccess` property on `FilterSecurityInterceptor`, you can use the following:
- [source,java]
- ----
- @Bean
- public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
- http
- .authorizeHttpRequests((authorize) -> authorize
- .anyRequest().authenticated()
- .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
- public <O extends FilterSecurityInterceptor> O postProcess(
- O fsi) {
- fsi.setPublishAuthorizationSuccess(true);
- return fsi;
- }
- })
- );
- return http.build();
- }
- ----
|