(window.webpackJsonp=window.webpackJsonp||[]).push([[262],{688:function(t,e,i){"use strict";i.r(e);var r=i(56),n=Object(r.a)({},(function(){var t=this,e=t.$createElement,i=t._self._c||e;return i("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[i("h1",{attrs:{id:"java-configuration"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#java-configuration"}},[t._v("#")]),t._v(" Java Configuration")]),t._v(" "),i("p",[t._v("General support for "),i("a",{attrs:{href:"https://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/beans.html#beans-java",target:"_blank",rel:"noopener noreferrer"}},[t._v("Java Configuration"),i("OutboundLink")],1),t._v(" was added to Spring Framework in Spring 3.1.\nSince Spring Security 3.2 there has been Spring Security Java Configuration support which enables users to easily configure Spring Security without the use of any XML.")]),t._v(" "),i("p",[t._v("If you are familiar with the "),i("RouterLink",{attrs:{to:"/en/spring-security/xml-namespace.html#ns-config"}},[t._v("Security Namespace Configuration")]),t._v(" then you should find quite a few similarities between it and the Security Java Configuration support.")],1),t._v(" "),i("table",[i("thead",[i("tr",[i("th"),t._v(" "),i("th",[t._v("Spring Security provides "),i("a",{attrs:{href:"https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration",target:"_blank",rel:"noopener noreferrer"}},[t._v("lots of sample applications"),i("OutboundLink")],1),t._v(" which demonstrate the use of Spring Security Java Configuration.")])])]),t._v(" "),i("tbody")]),t._v(" "),i("h2",{attrs:{id:"hello-web-security-java-configuration"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#hello-web-security-java-configuration"}},[t._v("#")]),t._v(" Hello Web Security Java Configuration")]),t._v(" "),i("p",[t._v("The first step is to create our Spring Security Java Configuration.\nThe configuration creates a Servlet Filter known as the "),i("code",[t._v("springSecurityFilterChain")]),t._v(" which is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the log in form, etc) within your application.\nYou can find the most basic example of a Spring Security Java Configuration below:")]),t._v(" "),i("div",{staticClass:"language- extra-class"},[i("pre",{pre:!0,attrs:{class:"language-text"}},[i("code",[t._v('import org.springframework.beans.factory.annotation.Autowired;\n\nimport org.springframework.context.annotation.*;\nimport org.springframework.security.config.annotation.authentication.builders.*;\nimport org.springframework.security.config.annotation.web.configuration.*;\n\n@EnableWebSecurity\npublic class WebSecurityConfig {\n\n\t@Bean\n\tpublic UserDetailsService userDetailsService() {\n\t\tInMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();\n\t\tmanager.createUser(User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build());\n\t\treturn manager;\n\t}\n}\n')])])]),i("p",[t._v("There really isn’t much to this configuration, but it does a lot.\nYou can find a summary of the features below:")]),t._v(" "),i("ul",[i("li",[i("p",[t._v("Require authentication to every URL in your application")])]),t._v(" "),i("li",[i("p",[t._v("Generate a login form for you")])]),t._v(" "),i("li",[i("p",[t._v("Allow the user with the "),i("strong",[t._v("Username")]),t._v(" "),i("em",[t._v("user")]),t._v(" and the "),i("strong",[t._v("Password")]),t._v(" "),i("em",[t._v("password")]),t._v(" to authenticate with form based authentication")])]),t._v(" "),i("li",[i("p",[t._v("Allow the user to logout")])]),t._v(" "),i("li",[i("p",[i("a",{attrs:{href:"https://en.wikipedia.org/wiki/Cross-site_request_forgery",target:"_blank",rel:"noopener noreferrer"}},[t._v("CSRF attack"),i("OutboundLink")],1),t._v(" prevention")])]),t._v(" "),i("li",[i("p",[i("a",{attrs:{href:"https://en.wikipedia.org/wiki/Session_fixation",target:"_blank",rel:"noopener noreferrer"}},[t._v("Session Fixation"),i("OutboundLink")],1),t._v(" protection")])]),t._v(" "),i("li",[i("p",[t._v("Security Header integration")]),t._v(" "),i("ul",[i("li",[i("p",[i("a",{attrs:{href:"https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security",target:"_blank",rel:"noopener noreferrer"}},[t._v("HTTP Strict Transport Security"),i("OutboundLink")],1),t._v(" for secure requests")])]),t._v(" "),i("li",[i("p",[i("a",{attrs:{href:"https://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx",target:"_blank",rel:"noopener noreferrer"}},[t._v("X-Content-Type-Options"),i("OutboundLink")],1),t._v(" integration")])]),t._v(" "),i("li",[i("p",[t._v("Cache Control (can be overridden later by your application to allow caching of your static resources)")])]),t._v(" "),i("li",[i("p",[i("a",{attrs:{href:"https://msdn.microsoft.com/en-us/library/dd565647(v=vs.85).aspx",target:"_blank",rel:"noopener noreferrer"}},[t._v("X-XSS-Protection"),i("OutboundLink")],1),t._v(" integration")])]),t._v(" "),i("li",[i("p",[t._v("X-Frame-Options integration to help prevent "),i("a",{attrs:{href:"https://en.wikipedia.org/wiki/Clickjacking",target:"_blank",rel:"noopener noreferrer"}},[t._v("Clickjacking"),i("OutboundLink")],1)])])])]),t._v(" "),i("li",[i("p",[t._v("Integrate with the following Servlet API methods")]),t._v(" "),i("ul",[i("li",[i("p",[i("a",{attrs:{href:"https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getRemoteUser()",target:"_blank",rel:"noopener noreferrer"}},[t._v("HttpServletRequest#getRemoteUser()"),i("OutboundLink")],1)])]),t._v(" "),i("li",[i("p",[i("a",{attrs:{href:"https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getUserPrincipal()",target:"_blank",rel:"noopener noreferrer"}},[t._v("HttpServletRequest#getUserPrincipal()"),i("OutboundLink")],1)])]),t._v(" "),i("li",[i("p",[i("a",{attrs:{href:"https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#isUserInRole(java.lang.String)",target:"_blank",rel:"noopener noreferrer"}},[t._v("HttpServletRequest#isUserInRole(java.lang.String)"),i("OutboundLink")],1)])]),t._v(" "),i("li",[i("p",[i("a",{attrs:{href:"https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#login(java.lang.String,%20java.lang.String)",target:"_blank",rel:"noopener noreferrer"}},[t._v("HttpServletRequest#login(java.lang.String, java.lang.String)"),i("OutboundLink")],1)])]),t._v(" "),i("li",[i("p",[i("a",{attrs:{href:"https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#logout()",target:"_blank",rel:"noopener noreferrer"}},[t._v("HttpServletRequest#logout()"),i("OutboundLink")],1)])])])])]),t._v(" "),i("h3",{attrs:{id:"abstractsecuritywebapplicationinitializer"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#abstractsecuritywebapplicationinitializer"}},[t._v("#")]),t._v(" AbstractSecurityWebApplicationInitializer")]),t._v(" "),i("p",[t._v("The next step is to register the "),i("code",[t._v("springSecurityFilterChain")]),t._v(" with the war.\nThis can be done in Java Configuration with "),i("a",{attrs:{href:"https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-container-config",target:"_blank",rel:"noopener noreferrer"}},[t._v("Spring’s WebApplicationInitializer support"),i("OutboundLink")],1),t._v(" in a Servlet 3.0+ environment.\nNot suprisingly, Spring Security provides a base class "),i("code",[t._v("AbstractSecurityWebApplicationInitializer")]),t._v(" that will ensure the "),i("code",[t._v("springSecurityFilterChain")]),t._v(" gets registered for you.\nThe way in which we use "),i("code",[t._v("AbstractSecurityWebApplicationInitializer")]),t._v(" differs depending on if we are already using Spring or if Spring Security is the only Spring component in our application.")]),t._v(" "),i("ul",[i("li",[i("p",[i("a",{attrs:{href:"#abstractsecuritywebapplicationinitializer-without-existing-spring"}},[t._v("AbstractSecurityWebApplicationInitializer without Existing Spring")]),t._v(" - Use these instructions if you are not using Spring already")])]),t._v(" "),i("li",[i("p",[i("a",{attrs:{href:"#abstractsecuritywebapplicationinitializer-with-spring-mvc"}},[t._v("AbstractSecurityWebApplicationInitializer with Spring MVC")]),t._v(" - Use these instructions if you are already using Spring")])])]),t._v(" "),i("h3",{attrs:{id:"abstractsecuritywebapplicationinitializer-without-existing-spring"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#abstractsecuritywebapplicationinitializer-without-existing-spring"}},[t._v("#")]),t._v(" AbstractSecurityWebApplicationInitializer without Existing Spring")]),t._v(" "),i("p",[t._v("If you are not using Spring or Spring MVC, you will need to pass in the "),i("code",[t._v("WebSecurityConfig")]),t._v(" into the superclass to ensure the configuration is picked up.\nYou can find an example below:")]),t._v(" "),i("div",{staticClass:"language- extra-class"},[i("pre",{pre:!0,attrs:{class:"language-text"}},[i("code",[t._v("import org.springframework.security.web.context.*;\n\npublic class SecurityWebApplicationInitializer\n\textends AbstractSecurityWebApplicationInitializer {\n\n\tpublic SecurityWebApplicationInitializer() {\n\t\tsuper(WebSecurityConfig.class);\n\t}\n}\n")])])]),i("p",[t._v("The "),i("code",[t._v("SecurityWebApplicationInitializer")]),t._v(" will do the following things:")]),t._v(" "),i("ul",[i("li",[i("p",[t._v("Automatically register the springSecurityFilterChain Filter for every URL in your application")])]),t._v(" "),i("li",[i("p",[t._v("Add a ContextLoaderListener that loads the "),i("a",{attrs:{href:"#jc-hello-wsca"}},[t._v("WebSecurityConfig")]),t._v(".")])])]),t._v(" "),i("h3",{attrs:{id:"abstractsecuritywebapplicationinitializer-with-spring-mvc"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#abstractsecuritywebapplicationinitializer-with-spring-mvc"}},[t._v("#")]),t._v(" AbstractSecurityWebApplicationInitializer with Spring MVC")]),t._v(" "),i("p",[t._v("If we were using Spring elsewhere in our application we probably already had a "),i("code",[t._v("WebApplicationInitializer")]),t._v(" that is loading our Spring Configuration.\nIf we use the previous configuration we would get an error.\nInstead, we should register Spring Security with the existing "),i("code",[t._v("ApplicationContext")]),t._v(".\nFor example, if we were using Spring MVC our "),i("code",[t._v("SecurityWebApplicationInitializer")]),t._v(" would look something like the following:")]),t._v(" "),i("div",{staticClass:"language- extra-class"},[i("pre",{pre:!0,attrs:{class:"language-text"}},[i("code",[t._v("import org.springframework.security.web.context.*;\n\npublic class SecurityWebApplicationInitializer\n\textends AbstractSecurityWebApplicationInitializer {\n\n}\n")])])]),i("p",[t._v("This would simply only register the springSecurityFilterChain Filter for every URL in your application.\nAfter that we would ensure that "),i("code",[t._v("WebSecurityConfig")]),t._v(" was loaded in our existing ApplicationInitializer.\nFor example, if we were using Spring MVC it would be added in the "),i("code",[t._v("getRootConfigClasses()")])]),t._v(" "),i("div",{staticClass:"language- extra-class"},[i("pre",{pre:!0,attrs:{class:"language-text"}},[i("code",[t._v("public class MvcWebApplicationInitializer extends\n\t\tAbstractAnnotationConfigDispatcherServletInitializer {\n\n\t@Override\n\tprotected Class[] getRootConfigClasses() {\n\t\treturn new Class[] { WebSecurityConfig.class };\n\t}\n\n\t// ... other overrides ...\n}\n")])])]),i("h2",{attrs:{id:"httpsecurity"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#httpsecurity"}},[t._v("#")]),t._v(" HttpSecurity")]),t._v(" "),i("p",[t._v("Thus far our "),i("a",{attrs:{href:"#jc-hello-wsca"}},[t._v("WebSecurityConfig")]),t._v(" only contains information about how to authenticate our users.\nHow does Spring Security know that we want to require all users to be authenticated?\nHow does Spring Security know we want to support form based authentication?\nActually, there is a configuration class that is being invoked behind the scenes called "),i("code",[t._v("WebSecurityConfigurerAdapter")]),t._v(".\nIt has a method called "),i("code",[t._v("configure")]),t._v(" with the following default implementation:")]),t._v(" "),i("div",{staticClass:"language- extra-class"},[i("pre",{pre:!0,attrs:{class:"language-text"}},[i("code",[t._v("protected void configure(HttpSecurity http) throws Exception {\n\thttp\n\t\t.authorizeRequests(authorize -> authorize\n\t\t\t.anyRequest().authenticated()\n\t\t)\n\t\t.formLogin(withDefaults())\n\t\t.httpBasic(withDefaults());\n}\n")])])]),i("p",[t._v("The default configuration above:")]),t._v(" "),i("ul",[i("li",[i("p",[t._v("Ensures that any request to our application requires the user to be authenticated")])]),t._v(" "),i("li",[i("p",[t._v("Allows users to authenticate with form based login")])]),t._v(" "),i("li",[i("p",[t._v("Allows users to authenticate with HTTP Basic authentication")])])]),t._v(" "),i("p",[t._v("You will notice that this configuration is quite similar the XML Namespace configuration:")]),t._v(" "),i("div",{staticClass:"language- extra-class"},[i("pre",{pre:!0,attrs:{class:"language-text"}},[i("code",[t._v('\n\t\n\t\n\t\n\n')])])]),i("h2",{attrs:{id:"multiple-httpsecurity"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#multiple-httpsecurity"}},[t._v("#")]),t._v(" Multiple HttpSecurity")]),t._v(" "),i("p",[t._v("We can configure multiple HttpSecurity instances just as we can have multiple "),i("code",[t._v("")]),t._v(" blocks.\nThe key is to extend the "),i("code",[t._v("WebSecurityConfigurerAdapter")]),t._v(" multiple times.\nFor example, the following is an example of having a different configuration for URL’s that start with "),i("code",[t._v("/api/")]),t._v(".")]),t._v(" "),i("div",{staticClass:"language- extra-class"},[i("pre",{pre:!0,attrs:{class:"language-text"}},[i("code",[t._v('@EnableWebSecurity\npublic class MultiHttpSecurityConfig {\n\t@Bean (1)\n\tpublic UserDetailsService userDetailsService() throws Exception {\n\t\t// ensure the passwords are encoded properly\n\t\tUserBuilder users = User.withDefaultPasswordEncoder();\n\t\tInMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();\n\t\tmanager.createUser(users.username("user").password("password").roles("USER").build());\n\t\tmanager.createUser(users.username("admin").password("password").roles("USER","ADMIN").build());\n\t\treturn manager;\n\t}\n\n\t@Configuration\n\t@Order(1) (2)\n\tpublic static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {\n\t\tprotected void configure(HttpSecurity http) throws Exception {\n\t\t\thttp\n\t\t\t\t.antMatcher("/api/**") (3)\n\t\t\t\t.authorizeHttpRequests(authorize -> authorize\n\t\t\t\t\t.anyRequest().hasRole("ADMIN")\n\t\t\t )\n\t\t\t\t.httpBasic(withDefaults());\n\t\t}\n\t}\n\n\t@Configuration (4)\n\tpublic static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {\n\n\t\t@Override\n\t\tprotected void configure(HttpSecurity http) throws Exception {\n\t\t\thttp\n\t\t\t\t.authorizeHttpRequests(authorize -> authorize\n\t\t\t\t\t.anyRequest().authenticated()\n\t\t\t\t)\n\t\t\t\t.formLogin(withDefaults());\n\t\t}\n\t}\n}\n')])])]),i("table",[i("thead",[i("tr",[i("th",[i("strong",[t._v("1")])]),t._v(" "),i("th",[t._v("Configure Authentication as normal")])])]),t._v(" "),i("tbody",[i("tr",[i("td",[i("strong",[t._v("2")])]),t._v(" "),i("td",[t._v("Create an instance of "),i("code",[t._v("WebSecurityConfigurerAdapter")]),t._v(" that contains "),i("code",[t._v("@Order")]),t._v(" to specify which "),i("code",[t._v("WebSecurityConfigurerAdapter")]),t._v(" should be considered first.")])]),t._v(" "),i("tr",[i("td",[i("strong",[t._v("3")])]),t._v(" "),i("td",[t._v("The "),i("code",[t._v("http.antMatcher")]),t._v(" states that this "),i("code",[t._v("HttpSecurity")]),t._v(" will only be applicable to URLs that start with "),i("code",[t._v("/api/")])])]),t._v(" "),i("tr",[i("td",[i("strong",[t._v("4")])]),t._v(" "),i("td",[t._v("Create another instance of "),i("code",[t._v("WebSecurityConfigurerAdapter")]),t._v("."),i("br"),t._v("If the URL does not start with "),i("code",[t._v("/api/")]),t._v(" this configuration will be used."),i("br"),t._v("This configuration is considered after "),i("code",[t._v("ApiWebSecurityConfigurationAdapter")]),t._v(" since it has an "),i("code",[t._v("@Order")]),t._v(" value after "),i("code",[t._v("1")]),t._v(" (no "),i("code",[t._v("@Order")]),t._v(" defaults to last).")])])])]),t._v(" "),i("h2",{attrs:{id:"custom-dsls"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#custom-dsls"}},[t._v("#")]),t._v(" Custom DSLs")]),t._v(" "),i("p",[t._v("You can provide your own custom DSLs in Spring Security.\nFor example, you might have something that looks like this:")]),t._v(" "),i("div",{staticClass:"language- extra-class"},[i("pre",{pre:!0,attrs:{class:"language-text"}},[i("code",[t._v("public class MyCustomDsl extends AbstractHttpConfigurer {\n\tprivate boolean flag;\n\n\t@Override\n\tpublic void init(HttpSecurity http) throws Exception {\n\t\t// any method that adds another configurer\n\t\t// must be done in the init method\n\t\thttp.csrf().disable();\n\t}\n\n\t@Override\n\tpublic void configure(HttpSecurity http) throws Exception {\n\t\tApplicationContext context = http.getSharedObject(ApplicationContext.class);\n\n\t\t// here we lookup from the ApplicationContext. You can also just create a new instance.\n\t\tMyFilter myFilter = context.getBean(MyFilter.class);\n\t\tmyFilter.setFlag(flag);\n\t\thttp.addFilterBefore(myFilter, UsernamePasswordAuthenticationFilter.class);\n\t}\n\n\tpublic MyCustomDsl flag(boolean value) {\n\t\tthis.flag = value;\n\t\treturn this;\n\t}\n\n\tpublic static MyCustomDsl customDsl() {\n\t\treturn new MyCustomDsl();\n\t}\n}\n")])])]),i("table",[i("thead",[i("tr",[i("th"),t._v(" "),i("th",[t._v("This is actually how methods like "),i("code",[t._v("HttpSecurity.authorizeRequests()")]),t._v(" are implemented.")])])]),t._v(" "),i("tbody")]),t._v(" "),i("p",[t._v("The custom DSL can then be used like this:")]),t._v(" "),i("div",{staticClass:"language- extra-class"},[i("pre",{pre:!0,attrs:{class:"language-text"}},[i("code",[t._v("@EnableWebSecurity\npublic class Config extends WebSecurityConfigurerAdapter {\n\t@Override\n\tprotected void configure(HttpSecurity http) throws Exception {\n\t\thttp\n\t\t\t.apply(customDsl())\n\t\t\t\t.flag(true)\n\t\t\t\t.and()\n\t\t\t...;\n\t}\n}\n")])])]),i("p",[t._v("The code is invoked in the following order:")]),t._v(" "),i("ul",[i("li",[i("p",[t._v("Code in "),i("code",[t._v("Config")]),t._v("s configure method is invoked")])]),t._v(" "),i("li",[i("p",[t._v("Code in "),i("code",[t._v("MyCustomDsl")]),t._v("s init method is invoked")])]),t._v(" "),i("li",[i("p",[t._v("Code in "),i("code",[t._v("MyCustomDsl")]),t._v("s configure method is invoked")])])]),t._v(" "),i("p",[t._v("If you want, you can have "),i("code",[t._v("WebSecurityConfigurerAdapter")]),t._v(" add "),i("code",[t._v("MyCustomDsl")]),t._v(" by default by using "),i("code",[t._v("SpringFactories")]),t._v(".\nFor example, you would create a resource on the classpath named "),i("code",[t._v("META-INF/spring.factories")]),t._v(" with the following contents:")]),t._v(" "),i("p",[t._v("META-INF/spring.factories")]),t._v(" "),i("div",{staticClass:"language- extra-class"},[i("pre",{pre:!0,attrs:{class:"language-text"}},[i("code",[t._v("org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer = sample.MyCustomDsl\n")])])]),i("p",[t._v("Users wishing to disable the default can do so explicitly.")]),t._v(" "),i("div",{staticClass:"language- extra-class"},[i("pre",{pre:!0,attrs:{class:"language-text"}},[i("code",[t._v("@EnableWebSecurity\npublic class Config extends WebSecurityConfigurerAdapter {\n\t@Override\n\tprotected void configure(HttpSecurity http) throws Exception {\n\t\thttp\n\t\t\t.apply(customDsl()).disable()\n\t\t\t...;\n\t}\n}\n")])])]),i("h2",{attrs:{id:"post-processing-configured-objects"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#post-processing-configured-objects"}},[t._v("#")]),t._v(" Post Processing Configured Objects")]),t._v(" "),i("p",[t._v("Spring Security’s Java Configuration does not expose every property of every object that it configures.\nThis simplifies the configuration for a majority of users.\nAfterall, if every property was exposed, users could use standard bean configuration.")]),t._v(" "),i("p",[t._v("While there are good reasons to not directly expose every property, users may still need more advanced configuration options.\nTo address this Spring Security introduces the concept of an "),i("code",[t._v("ObjectPostProcessor")]),t._v(" which can be used to modify or replace many of the Object instances created by the Java Configuration.\nFor example, if you wanted to configure the "),i("code",[t._v("filterSecurityPublishAuthorizationSuccess")]),t._v(" property on "),i("code",[t._v("FilterSecurityInterceptor")]),t._v(" you could use the following:")]),t._v(" "),i("div",{staticClass:"language- extra-class"},[i("pre",{pre:!0,attrs:{class:"language-text"}},[i("code",[t._v("@Override\nprotected void configure(HttpSecurity http) throws Exception {\n\thttp\n\t\t.authorizeRequests(authorize -> authorize\n\t\t\t.anyRequest().authenticated()\n\t\t\t.withObjectPostProcessor(new ObjectPostProcessor() {\n\t\t\t\tpublic O postProcess(\n\t\t\t\t\t\tO fsi) {\n\t\t\t\t\tfsi.setPublishAuthorizationSuccess(true);\n\t\t\t\t\treturn fsi;\n\t\t\t\t}\n\t\t\t})\n\t\t);\n}\n")])])]),i("p",[i("RouterLink",{attrs:{to:"/en/integrations/jsp-taglibs.html"}},[t._v("JSP Taglib")]),i("RouterLink",{attrs:{to:"/en/spring-security/kotlin.html"}},[t._v("Kotlin Configuration")])],1)])}),[],!1,null,null,null);e.default=n.exports}}]);