Intereting Posts

Включение безопасности глобальной безопасности Spring Security нарушает инъекцию зависимостей (с Kotlin)

В настоящее время я работаю над системой аутентификации для приложения Spring Boot, и у меня возникли проблемы с тех пор, как я попытался включить глобальную защиту безопасности Spring Security.

Приложение Spring Boot, являющееся REST API, система аутентификации немного нестандартна, поэтому я настроил собственный фильтр проверки подлинности, который добавляю к объекту HttpSecurity который предварительно обрабатывает запрос, вызывает пользовательский AuthenticationManager и дает окончательный Объект Authentication в SecurityContextHolder . И это прекрасно работает!

Однако с помощью этого метода я должен настроить все правила доступа для своих конечных точек непосредственно в моем переопределенном методе WebSecurityConfigurerAdapter.configure , который я считаю менее практичным, поэтому я попытался использовать аннотацию Spring Security @PreAuthorize непосредственно в моих контроллерах вместо.

Проблема в том, что если я добавлю @EnableGlobalMethodSecurity(prePostEnabled = true) в мою конфигурацию безопасности, все атрибуты @Autowired в моих контроллерах не будут введены. Он отлично работает, если я устанавливаю prePostEnabled = false или вообще prePostEnabled = false аннотацию, но, конечно, это не то, что я хочу.

Здесь находится стек, который показывает вызывающий обработчик запроса (и атрибуты, которые не инициализируются):

 kotlin.UninitializedPropertyAccessException: lateinit property accountService has not been initialized at com.example.api.module.account.AccountController.addAccountRole(AccountController.kt:105) ~[main/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_121] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_121] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_121] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_121] at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:648) ~[tomcat-embed-core-8.5.11.jar:8.5.11] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) ~[tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230) ~[tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.11.jar:8.5.11] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11] at com.example.api.security.HeaderAuthenticationFilter.doFilter(HeaderAuthenticationFilter.kt:46) ~[main/:na] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at com.example.api.security.HeaderAuthenticationFilter.doFilter(HeaderAuthenticationFilter.kt:46) ~[main/:na] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE] at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11] at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11] at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474) [tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349) [tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783) [tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:798) [tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1434) [tomcat-embed-core-8.5.11.jar:8.5.11] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.11.jar:8.5.11] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_121] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_121] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.11.jar:8.5.11] at java.lang.Thread.run(Thread.java:745) [na:1.8.0_121] 

И вот некоторые из моих классов, которые, я думаю, актуальны со всеми их аннотациями, чтобы проиллюстрировать мои объяснения.

com / example / api / security / SecurityConfig.kt:

 @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) // works if absent open class WebSecurityConfig : WebSecurityConfigurerAdapter() { @Autowired lateinit var authFilter: HeaderAuthenticationFilter override fun configure(http: HttpSecurity) { http.addFilterAt(authFilter, AbstractPreAuthenticatedProcessingFilter::class.java) .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) http.authorizeRequests() .antMatchers(HttpMethod.POST, "/accounts").permitAll() .anyRequest().authenticated() http.csrf().disable() } } 

com / example / api / module / account / AccountController.kt:

 @RestController @RequestMapping("/accounts") open class AccountController { @Autowired lateinit var accountService: AccountService // [...] @PreAuthorize("hasAuthority('ADMIN') or hasIpAddress('127.0.0.1')") @RequestMapping(method = arrayOf(RequestMethod.POST), value = "/{id}/roles") fun addAccountRole(@RequestBody data: PostAccountRoleData, @PathVariable("id") id: Long): ResponseWrapper { val account = accountService.findAccount(id) // line 105, exception here accountService.updateAccount(account.copy(authority = data.roles)) return ResponseWrapper(StatusMessage.SUCCESS) } } 

com / example / api / module / account / AccountService.kt:

 interface AccountService { fun getAllAccounts(): List<Account> fun findAccount(id: Long): Account // [...] } 

com / example / api / module / account / DatastoreAccountService.kt:

 @Service("accountService") class DatastoreAccountService : AccountService { // [...] implementation details } 

Итак, как я могу это решить? Я знаю, что активация глобальной безопасности методов активирует какой-то прокси-сервер, но я понятия не имею, почему и как это может повлиять на инъекцию зависимостей на моих контроллерах.

Заранее спасибо!

EDIT: Вот мой файл build.gradle:

 group 'com.example.api' version '1.0-SNAPSHOT' buildscript { ext.kotlin_version = '1.1.1' ext.spring_boot_version = '1.5.2.RELEASE' ext.spring_security_version = '4.2.2.RELEASE' ext.jackson_kotlin_version = '2.9.0.pr2' repositories { jcenter() mavenCentral() } dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.springframework.boot:spring-boot-gradle-plugin:$spring_boot_version" classpath 'com.google.cloud.tools:appengine-gradle-plugin:+' } } repositories { maven { url 'https://maven-central.storage.googleapis.com' } jcenter() mavenCentral() } apply plugin: 'kotlin' apply plugin: 'idea' apply plugin: 'eclipse' apply plugin: 'org.springframework.boot' apply plugin: 'com.google.cloud.tools.appengine' dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" compile 'org.springframework.boot:spring-boot-starter-web' compile "org.springframework.security:spring-security-web:$spring_security_version" compile "org.springframework.security:spring-security-config:$spring_security_version" compile "com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_kotlin_version" compile 'com.google.cloud:google-cloud-datastore:+' } jar { baseName = 'example-api' version = "$version" } appengine { deploy { stopPreviousVersion = true promote = true } } sourceCompatibility = 1.8 targetCompatibility = 1.8 // Set-up the datastore emulator environment variable for debugging bootRun { environment "DATASTORE_EMULATOR_HOST", "localhost:8081" environment "DATASTORE_PROJECT_ID", "example-api" } 

вы должны использовать kapt в своем файле gradle для moxy-компилятора.

Наиболее стабильная конфигурация kapt с генерируемыми заглушками приведена в следующем примере

 apply plugin: 'com.android.application' apply plugin: 'kotlin-android' android { compileSdkVersion 24 buildToolsVersion "24.0.0" defaultConfig { applicationId "com.redmadrobot.moxysamplekotlin" minSdkVersion 19 targetSdkVersion 24 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } kapt { generateStubs = true } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:24.2.1' compile 'com.android.support:design:24.2.1' compile project(':moxy') compile project(':moxy-android') kapt project(':moxy-compiler') testCompile 'junit:junit:4.12' compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" } 

Для получения полной информации, пожалуйста, проверьте эту проблему github: свойство lateinit Presenter не было инициализировано

Хорошо, мне удалось это исправить.

Я думаю, что проблема заключалась в том, что, хотя мой AccountController был объявлен open , некоторые из моих классов Kotlin не были (для тех, кто не знаком с Kotlin, это означает, что эти классы были объявлены final в JVM), и это возилось с зависимостью как-то (возможно, какая-то странность CGLIB?). Я не думал, что проблема придет отсюда, потому что обычно Spring генерирует исключение, когда ему не удается ввести зависимость по таким причинам, но в этом случае этого не произошло. Это может быть или не быть нормальным, но у меня недостаточно знаний о внутренних функциях Spring, чтобы иметь возможность сказать, что недостаток брошенного исключения является ошибкой.

Во всяком случае, вернемся к нашей проблеме. Один из способов исправить это (я думаю), не добавляя больше зависимостей, – это пройти весь ваш код и отметить Spring-аннотированные классы (и, возможно, подклассы тоже), как open для них, чтобы отказаться от их final .

Тем не менее, JetBrains выпустил плагин компилятора под названием kotlin-allopen для автоматического объявления классов с конкретными аннотациями как open , и вы даже можете использовать kotlin-spring для автоматической настройки его с помощью аннотаций Spring!

Таким образом, другой, более простой способ исправить это – добавить это в свой build.gradle (есть также версия maven):

 // Add to dependencies classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version" // [...] apply plugin: 'kotlin-spring'