| 
					
				 | 
			
			
				@@ -38,7 +38,7 @@ open fun filterChain(http: HttpSecurity): SecurityFilterChain { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 [NOTE] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 Make sure to import the `org.springframework.security.config.annotation.web.invoke` function to enable the Kotlin DSL in your class, as the IDE will not always auto-import the method, causing compilation issues. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-The default configuration (shown in the preceding listing): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+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 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -55,12 +55,16 @@ Note that this configuration parallels the XML namespace configuration: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 </http> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-== Multiple HttpSecurity Instances 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+=== Multiple HttpSecurity Instances 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-We can configure multiple `HttpSecurity` instances, just as we can have multiple `<http>` blocks. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+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 start with `/api/`: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+The following example has a different configuration for URLs that begin with `/api/`: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+[[multiple-httpsecurity-instances-kotlin]] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 [source,kotlin] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import org.springframework.security.config.annotation.web.invoke 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -69,16 +73,16 @@ import org.springframework.security.config.annotation.web.invoke 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 @EnableWebSecurity 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 class MultiHttpSecurityConfig { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @Bean                                                            <1> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    public fun userDetailsService(): UserDetailsService { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        val users: User.UserBuilder = User.withDefaultPasswordEncoder() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    open fun userDetailsService(): UserDetailsService { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        val users = User.withDefaultPasswordEncoder() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         val manager = InMemoryUserDetailsManager() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         manager.createUser(users.username("user").password("password").roles("USER").build()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         manager.createUser(users.username("admin").password("password").roles("USER","ADMIN").build()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return manager 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    @Order(1)                                                        <2> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @Bean 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Order(1)                                                        <2> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     open fun apiFilterChain(http: HttpSecurity): SecurityFilterChain { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         http { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             securityMatcher("/api/**")                               <3> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -102,10 +106,243 @@ class MultiHttpSecurityConfig { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 <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 start with `/api/` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<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 start with `/api/`, this configuration is used. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+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-kotlin]] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+[source,kotlin] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.config.annotation.web.invoke 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Configuration 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@EnableWebSecurity 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+class PartialSecurityConfig { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Bean 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	open fun userDetailsService(): UserDetailsService { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// ... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Bean 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	open fun securedFilterChain(http: HttpSecurity): SecurityFilterChain { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		http { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			securityMatcher("/secured/**")                             <1> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			authorizeHttpRequests { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				authorize("/secured/user", hasRole("USER"))            <2> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				authorize("/secured/admin", hasRole("ADMIN"))          <3> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				authorize(anyRequest, authenticated)                   <4> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			httpBasic { } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			formLogin { } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		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-kotlin,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-kotlin,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-kotlin]] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+[source,kotlin] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.config.annotation.web.invoke 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Configuration 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@EnableWebSecurity 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+class SecuredSecurityConfig { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Bean 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	open fun userDetailsService(): UserDetailsService { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// ... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Bean 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Order(1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	open fun securedFilterChain(http: HttpSecurity): SecurityFilterChain { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		http { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			securityMatcher("/secured/**")                             <1> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			authorizeHttpRequests { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				authorize(anyRequest, authenticated)                   <2> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			formLogin {                                                <3> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                loginPage = "/secured/login" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                loginProcessingUrl = "/secured/login" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                permitAll = true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			logout {                                                   <4> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                logoutUrl = "/secured/logout" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                logoutSuccessUrl = "/secured/login?logout" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                permitAll = true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return http.build() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Bean 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    open fun defaultFilterChain(http: HttpSecurity): SecurityFilterChain { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        http { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            authorizeHttpRequests { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                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-kotlin]] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+[source,kotlin] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+---- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.config.annotation.web.invoke 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Configuration 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@EnableWebSecurity 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+class BankingSecurityConfig { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Bean                                                              <1> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    open fun userDetailsService(): UserDetailsService { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        val users = User.withDefaultPasswordEncoder() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        val manager = 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> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    open fun approvalsSecurityFilterChain(http: HttpSecurity): SecurityFilterChain { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        val approvalsPaths = arrayOf("/accounts/approvals/**", "/loans/approvals/**", "/credit-cards/approvals/**") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        http { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            securityMatcher(approvalsPaths) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            authorizeHttpRequests { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				authorize(anyRequest, hasRole("ADMIN")) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            httpBasic { } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return http.build() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Bean 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Order(2)                                                          <3> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	open fun bankingSecurityFilterChain(http: HttpSecurity): SecurityFilterChain { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        val bankingPaths = arrayOf("/accounts/**", "/loans/**", "/credit-cards/**", "/balances/**") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		val viewBalancePaths = arrayOf("/balances/**") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        http { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            securityMatcher(bankingPaths) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            authorizeHttpRequests { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                authorize(viewBalancePaths, hasRole("VIEW_BALANCE")) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				authorize(anyRequest, hasRole("USER")) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return http.build() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Bean                                                              <4> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	open fun defaultSecurityFilterChain(http: HttpSecurity): SecurityFilterChain { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        val allowedPaths = arrayOf("/", "/user-login", "/user-logout", "/notices", "/contact", "/register") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        http { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            authorizeHttpRequests { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                authorize(allowedPaths, permitAll) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				authorize(anyRequest, authenticated) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			formLogin { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                loginPage = "/user-login" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                loginProcessingUrl = "/user-login" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			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. 
			 |