Недавно я обновил свое приложение Spring Boot до Spring Boot 3 (с 2.6.4), Kotlin 1.8.0 (с 1.7.20) и JDK 17 (с 11). Прямо сейчас я сталкиваюсь с исключениями AnnotationConfigurationExceptions, вызванными метааннотациями @PreAuthorize, используемыми в унаследованных методах репозитория.
org.springframework.core.annotation.AnnotationConfigurationException: Found more than one annotation of type interface org.springframework.security.access.prepost.PreAuthorize attributed to public final java.util.List jdk.proxy2.$Proxy390.findAll() Please remove the duplicate annotations and publish a bean to handle your authorization logic.
at org.springframework.security.authorization.method.AuthorizationAnnotationUtils.findUniqueAnnotation(AuthorizationAnnotationUtils.java:64)
at org.springframework.security.authorization.method.PreAuthorizeExpressionAttributeRegistry.findPreAuthorizeAnnotation(PreAuthorizeExpressionAttributeRegistry.java:71)
at org.springframework.security.authorization.method.PreAuthorizeExpressionAttributeRegistry.resolveAttribute(PreAuthorizeExpressionAttributeRegistry.java:61)
at org.springframework.security.authorization.method.AbstractExpressionAttributeRegistry.lambda$getAttribute$0(AbstractExpressionAttributeRegistry.java:57)
at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708)
at org.springframework.security.authorization.method.AbstractExpressionAttributeRegistry.getAttribute(AbstractExpressionAttributeRegistry.java:57)
at org.springframework.security.authorization.method.AbstractExpressionAttributeRegistry.getAttribute(AbstractExpressionAttributeRegistry.java:46)
at org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager.check(PreAuthorizeAuthorizationManager.java:63)
at org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager.check(PreAuthorizeAuthorizationManager.java:40)
at org.springframework.security.authorization.ObservationAuthorizationManager.check(ObservationAuthorizationManager.java:55)
at org.springframework.security.config.annotation.method.configuration.DeferringObservationAuthorizationManager.check(DeferringObservationAuthorizationManager.java:47)
at org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor.attemptAuthorization(AuthorizationManagerBeforeMethodInterceptor.java:252)
at org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor.invoke(AuthorizationManagerBeforeMethodInterceptor.java:198)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
После некоторой отладки я обнаружил, что Spring Security каким-то образом отражает одну аннотацию несколько раз. Как только я перемещаю методы из базового репозитория в реальный репозиторий, исключение больше не появляется.
У меня есть базовый репозиторий, реализующий некоторые распространенные методы, такие как findAll, findById и т. д., помечая их доступными с помощью REST-API и ограничивая доступ с помощью метааннотации @HasRoleAdminOrHasReadCollectionPermission (позже):
@NoRepositoryBean
interface BaseRepository : CrudRepository {
/* [...] */
@RestResource
@HasRoleAdminOrHasReadCollectionPermission
override fun findAll(): List
/* [...] */
}
Во-вторых, базовый репозиторий реализуется фактическим репозиторием сущностей:
@RepositoryRestResource(path = "categories", collectionResourceRel = "categories")
@Transactional(readOnly = true)
interface CategoryRepository : BaseRepository {
/* [...] */
}
В-третьих, вот метааннотация @HasRoleAdminOrHasReadCollectionPermission:
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@PreAuthorize("hasRole('$ROLE_ADMIN') or hasPermission($COLLECTION_TARGET, $DELETE_PERMISSION)")
annotation class HasRoleAdminOrHasDeleteCollectionPermission
У меня закончились идеи, просмотрел Java-файлы, сгенерированные из Kotlin, нигде не дублируются аннотации. Надеюсь, кто-нибудь здесь сможет мне в этом помочь.
Изменить: в соответствии с просьбой, вот класс приложения и класс, содержащий конфигурацию безопасности:
@SpringBootApplication(exclude = [ErrorMvcAutoConfiguration::class])
@ServletComponentScan
@EnableAsync
@EnableScheduling
class Application {
companion object {
val HOSTNAME = System.getenv("HOSTNAME")
val TIMESTAMP = System.currentTimeMillis()
/** Entry point, run with gradle `bootRun` task. */
@JvmStatic
fun main(args: Array) {
SpringApplication.run(Application::class.java, *args)
}
}
}
@Configuration
@EnableWebSecurity(debug = true)
@EnableMethodSecurity(prePostEnabled = true)
class SecurityConfig(
private val environment: Environment,
private val baseProperties: BaseProperties,
private val accountService: AccountService,
private val integrationService: IntegrationService,
private val jwtService: JwtService,
private val loginAttemptService: LoginAttemptService,
private val handlerExceptionResolver: HandlerExceptionResolver
) {
@Bean
fun webSecurityCustomizer(): WebSecurityCustomizer =
WebSecurityCustomizer { web: WebSecurity -> web.debug(true) }
@Bean
fun corsConfigurationSource(): CorsConfigurationSource {
val configuration = CorsConfiguration()
configuration.allowedOrigins = baseProperties.corsAllowedOrigins()
configuration.allowedMethods = listOf(CorsConfiguration.ALL)
configuration.allowedHeaders = listOf(CorsConfiguration.ALL)
configuration.allowCredentials = true
val source = UrlBasedCorsConfigurationSource()
source.registerCorsConfiguration(ANY_PATH, configuration)
return source
}
@Bean
fun userDetailsService(): UserDetailsService =
AccountUserDetailsService(accountService, integrationService)
@Bean
fun authenticationManager(
http: HttpSecurity,
userDetailsService: UserDetailsService
): AuthenticationManager {
val authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder::class.java)
val loginAttemptDaoAuthenticationProvider = LoginAttemptDaoAuthenticationProvider(loginAttemptService, userDetailsService)
val jwtPreAuthenticationProvider = PreAuthenticatedAuthenticationProvider()
jwtPreAuthenticationProvider.setPreAuthenticatedUserDetailsService(UserDetailsByNameServiceWrapper(userDetailsService))
return authenticationManagerBuilder
.userDetailsService(userDetailsService).and()
.authenticationProvider(loginAttemptDaoAuthenticationProvider)
.authenticationProvider(jwtPreAuthenticationProvider)
.build()
}
@Bean
fun filterChain(
http: HttpSecurity,
authenticationManager: AuthenticationManager,
userDetailsService: UserDetailsService
): SecurityFilterChain {
return http
.requireSSL()
.disableLocalHSTS()
.enableCors()
.enableStatelessCsrf()
.statelessSessionManagement()
.jwtAuthentication(authenticationManager)
.setRequestRestrictions()
.build()
}
private fun HttpSecurity.requireSSL(): HttpSecurity =
requiresChannel().anyRequest().requiresSecure().and()
private fun HttpSecurity.disableLocalHSTS(): HttpSecurity =
if (environment.acceptsProfiles(Profiles.of(DEVELOPMENT, TESTING)))
headers().httpStrictTransportSecurity().disable().and()
else this
private fun HttpSecurity.enableCors(): HttpSecurity =
cors().and()
private fun HttpSecurity.enableStatelessCsrf(): HttpSecurity =
csrf().disable().addFilterBefore(StatelessCsrfFilter(), CsrfFilter::class.java)
private fun HttpSecurity.statelessSessionManagement(): HttpSecurity =
sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
private fun HttpSecurity.jwtAuthentication(
authenticationManager: AuthenticationManager
): HttpSecurity =
addFilterBefore(JwtPreAuthenticatedProcessingFilter(authenticationManager, jwtService), UsernamePasswordAuthenticationFilter::class.java)
.addFilterBefore(JwtCookiePreAuthenticationFilter(jwtService), UsernamePasswordAuthenticationFilter::class.java)
.formLogin()
.loginProcessingUrl(LOGIN_URL)
.successHandler(JwtCookieAuthenticationSuccessHandler(jwtService))
.failureHandler(AuthenticationFailureResolver(handlerExceptionResolver))
.and()
.logout()
.logoutUrl(LOGOUT_URL)
.logoutSuccessHandler(Http200LogoutSuccessHandler())
.addLogoutHandler(JwtCookieLogoutHandler(jwtService))
.and()
private fun HttpSecurity.setRequestRestrictions(): HttpSecurity =
authorizeHttpRequests {
it.requestMatchers(HttpMethod.GET, ROOT_URL).permitAll()
.requestMatchers([...])
.anyRequest().denyAll().and()
}
}
Подробнее здесь: https://stackoverflow.com/questions/751 ... t-3-jdk-17
AnnotationConfigurationException после обновления до Spring Boot 3/JDK 17 ⇐ JAVA
Программисты JAVA общаются здесь
1730590477
Anonymous
Недавно я обновил свое приложение Spring Boot до Spring Boot 3 (с 2.6.4), Kotlin 1.8.0 (с 1.7.20) и JDK 17 (с 11). Прямо сейчас я сталкиваюсь с исключениями AnnotationConfigurationExceptions, вызванными метааннотациями @PreAuthorize, используемыми в унаследованных методах репозитория.
org.springframework.core.annotation.AnnotationConfigurationException: Found more than one annotation of type interface org.springframework.security.access.prepost.PreAuthorize attributed to public final java.util.List jdk.proxy2.$Proxy390.findAll() Please remove the duplicate annotations and publish a bean to handle your authorization logic.
at org.springframework.security.authorization.method.AuthorizationAnnotationUtils.findUniqueAnnotation(AuthorizationAnnotationUtils.java:64)
at org.springframework.security.authorization.method.PreAuthorizeExpressionAttributeRegistry.findPreAuthorizeAnnotation(PreAuthorizeExpressionAttributeRegistry.java:71)
at org.springframework.security.authorization.method.PreAuthorizeExpressionAttributeRegistry.resolveAttribute(PreAuthorizeExpressionAttributeRegistry.java:61)
at org.springframework.security.authorization.method.AbstractExpressionAttributeRegistry.lambda$getAttribute$0(AbstractExpressionAttributeRegistry.java:57)
at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708)
at org.springframework.security.authorization.method.AbstractExpressionAttributeRegistry.getAttribute(AbstractExpressionAttributeRegistry.java:57)
at org.springframework.security.authorization.method.AbstractExpressionAttributeRegistry.getAttribute(AbstractExpressionAttributeRegistry.java:46)
at org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager.check(PreAuthorizeAuthorizationManager.java:63)
at org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager.check(PreAuthorizeAuthorizationManager.java:40)
at org.springframework.security.authorization.ObservationAuthorizationManager.check(ObservationAuthorizationManager.java:55)
at org.springframework.security.config.annotation.method.configuration.DeferringObservationAuthorizationManager.check(DeferringObservationAuthorizationManager.java:47)
at org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor.attemptAuthorization(AuthorizationManagerBeforeMethodInterceptor.java:252)
at org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor.invoke(AuthorizationManagerBeforeMethodInterceptor.java:198)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
После некоторой отладки я обнаружил, что Spring Security каким-то образом отражает одну аннотацию несколько раз. Как только я перемещаю методы из базового репозитория в реальный репозиторий, исключение больше не появляется.
У меня есть базовый репозиторий, реализующий некоторые распространенные методы, такие как findAll, findById и т. д., помечая их доступными с помощью REST-API и ограничивая доступ с помощью метааннотации @HasRoleAdminOrHasReadCollectionPermission (позже):
@NoRepositoryBean
interface BaseRepository : CrudRepository {
/* [...] */
@RestResource
@HasRoleAdminOrHasReadCollectionPermission
override fun findAll(): List
/* [...] */
}
Во-вторых, базовый репозиторий реализуется фактическим репозиторием сущностей:
@RepositoryRestResource(path = "categories", collectionResourceRel = "categories")
@Transactional(readOnly = true)
interface CategoryRepository : BaseRepository {
/* [...] */
}
В-третьих, вот метааннотация @HasRoleAdminOrHasReadCollectionPermission:
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@PreAuthorize("hasRole('$ROLE_ADMIN') or hasPermission($COLLECTION_TARGET, $DELETE_PERMISSION)")
annotation class HasRoleAdminOrHasDeleteCollectionPermission
У меня закончились идеи, просмотрел Java-файлы, сгенерированные из Kotlin, нигде не дублируются аннотации. Надеюсь, кто-нибудь здесь сможет мне в этом помочь.
Изменить: в соответствии с просьбой, вот класс приложения и класс, содержащий конфигурацию безопасности:
@SpringBootApplication(exclude = [ErrorMvcAutoConfiguration::class])
@ServletComponentScan
@EnableAsync
@EnableScheduling
class Application {
companion object {
val HOSTNAME = System.getenv("HOSTNAME")
val TIMESTAMP = System.currentTimeMillis()
/** Entry point, run with gradle `bootRun` task. */
@JvmStatic
fun main(args: Array) {
SpringApplication.run(Application::class.java, *args)
}
}
}
@Configuration
@EnableWebSecurity(debug = true)
@EnableMethodSecurity(prePostEnabled = true)
class SecurityConfig(
private val environment: Environment,
private val baseProperties: BaseProperties,
private val accountService: AccountService,
private val integrationService: IntegrationService,
private val jwtService: JwtService,
private val loginAttemptService: LoginAttemptService,
private val handlerExceptionResolver: HandlerExceptionResolver
) {
@Bean
fun webSecurityCustomizer(): WebSecurityCustomizer =
WebSecurityCustomizer { web: WebSecurity -> web.debug(true) }
@Bean
fun corsConfigurationSource(): CorsConfigurationSource {
val configuration = CorsConfiguration()
configuration.allowedOrigins = baseProperties.corsAllowedOrigins()
configuration.allowedMethods = listOf(CorsConfiguration.ALL)
configuration.allowedHeaders = listOf(CorsConfiguration.ALL)
configuration.allowCredentials = true
val source = UrlBasedCorsConfigurationSource()
source.registerCorsConfiguration(ANY_PATH, configuration)
return source
}
@Bean
fun userDetailsService(): UserDetailsService =
AccountUserDetailsService(accountService, integrationService)
@Bean
fun authenticationManager(
http: HttpSecurity,
userDetailsService: UserDetailsService
): AuthenticationManager {
val authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder::class.java)
val loginAttemptDaoAuthenticationProvider = LoginAttemptDaoAuthenticationProvider(loginAttemptService, userDetailsService)
val jwtPreAuthenticationProvider = PreAuthenticatedAuthenticationProvider()
jwtPreAuthenticationProvider.setPreAuthenticatedUserDetailsService(UserDetailsByNameServiceWrapper(userDetailsService))
return authenticationManagerBuilder
.userDetailsService(userDetailsService).and()
.authenticationProvider(loginAttemptDaoAuthenticationProvider)
.authenticationProvider(jwtPreAuthenticationProvider)
.build()
}
@Bean
fun filterChain(
http: HttpSecurity,
authenticationManager: AuthenticationManager,
userDetailsService: UserDetailsService
): SecurityFilterChain {
return http
.requireSSL()
.disableLocalHSTS()
.enableCors()
.enableStatelessCsrf()
.statelessSessionManagement()
.jwtAuthentication(authenticationManager)
.setRequestRestrictions()
.build()
}
private fun HttpSecurity.requireSSL(): HttpSecurity =
requiresChannel().anyRequest().requiresSecure().and()
private fun HttpSecurity.disableLocalHSTS(): HttpSecurity =
if (environment.acceptsProfiles(Profiles.of(DEVELOPMENT, TESTING)))
headers().httpStrictTransportSecurity().disable().and()
else this
private fun HttpSecurity.enableCors(): HttpSecurity =
cors().and()
private fun HttpSecurity.enableStatelessCsrf(): HttpSecurity =
csrf().disable().addFilterBefore(StatelessCsrfFilter(), CsrfFilter::class.java)
private fun HttpSecurity.statelessSessionManagement(): HttpSecurity =
sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
private fun HttpSecurity.jwtAuthentication(
authenticationManager: AuthenticationManager
): HttpSecurity =
addFilterBefore(JwtPreAuthenticatedProcessingFilter(authenticationManager, jwtService), UsernamePasswordAuthenticationFilter::class.java)
.addFilterBefore(JwtCookiePreAuthenticationFilter(jwtService), UsernamePasswordAuthenticationFilter::class.java)
.formLogin()
.loginProcessingUrl(LOGIN_URL)
.successHandler(JwtCookieAuthenticationSuccessHandler(jwtService))
.failureHandler(AuthenticationFailureResolver(handlerExceptionResolver))
.and()
.logout()
.logoutUrl(LOGOUT_URL)
.logoutSuccessHandler(Http200LogoutSuccessHandler())
.addLogoutHandler(JwtCookieLogoutHandler(jwtService))
.and()
private fun HttpSecurity.setRequestRestrictions(): HttpSecurity =
authorizeHttpRequests {
it.requestMatchers(HttpMethod.GET, ROOT_URL).permitAll()
.requestMatchers([...])
.anyRequest().denyAll().and()
}
}
Подробнее здесь: [url]https://stackoverflow.com/questions/75102645/annotationconfigurationexception-since-upgrade-to-spring-boot-3-jdk-17[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия