Доступ к bean-компоненту с помощью SpEL в @PreAuthorize с помощью FullyQualifiedAnnotationBeanNameGenerator
У меня есть контроллер с методом, который имеет логику для проверки разрешения:
@RestController
@RequestMapping("/example")
public class ExampleController {
@GetMapping
@PreAuthorize("@exampleController.hasPermission()")
public String example() {
return "hello";
}
public boolean hasPermission() {
return true; // complex logic
}
}
Как видите, я использую SpEL для вызова этого метода (по имени компонента:exampleController
).
Но если я изменю генератор имен компонентов наFullyQualifiedAnnotationBeanNameGenerator
:
@SpringBootApplication(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
теперь имя боба такоеcom.example.demo.ExampleController
(проверено в отладчике).
После этого я пытаюсь изменить имя компонента в@PreAuthorized
:
@PreAuthorize("@com.example.demo.ExampleController.hasPermission()")
но это не работает:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
[Request processing failed; nested exception is java.lang.IllegalArgumentException:
Failed to evaluate expression '@com.example.demo.ExampleController.hasPermission()'] with root cause
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'com' available
Как сослаться на компонент с точками в имени в SpEL? Или как вызвать метод из контроллера по-другому (без использования имени компонента)?
Я знаю, что могу реализовать индивидуальныйAnnotationBeanNameGenerator
без специальных символов. Но я ожидаю, что генератор имен компонентов Spring совместим с SpEL (языком выражений Spring).
Обновлять
Ответы на это и это тоже не работают (думаю, это работало в конфигурации XML, но не в аннотациях):
@PreAuthorize("#{@'com.example.demo.ExampleController'.hasPermission()}")
Initialization of bean failed; nested exception is java.lang.IllegalArgumentException:
Failed to parse expression '#{@'com.example.demo.ExampleController'.hasPermission()}'
Обновление 2
Полная трассировка стека (для @dur):
ERROR [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.example.demo.ExampleController' defined in file [(...)/demo/target/classes/com/example/demo/ExampleController.class]: Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: Failed to parse expression '#{@'com.example.demo.ExampleController'.hasPermission()}'
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:628) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.23.jar:5.3.23]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.23.jar:5.3.23]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.5.jar:2.7.5]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) ~[spring-boot-2.7.5.jar:2.7.5]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) ~[spring-boot-2.7.5.jar:2.7.5]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[spring-boot-2.7.5.jar:2.7.5]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.5.jar:2.7.5]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.5.jar:2.7.5]
at com.example.demo.DemoApplication.main(DemoApplication.java:11) ~[classes/:na]
Caused by: java.lang.IllegalArgumentException: Failed to parse expression '#{@'com.example.demo.ExampleController'.hasPermission()}'
at org.springframework.security.access.expression.method.ExpressionBasedAnnotationAttributeFactory.createPreInvocationAttribute(ExpressionBasedAnnotationAttributeFactory.java:59) ~[spring-security-core-5.7.4.jar:5.7.4]
at org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource.getAttributes(PrePostAnnotationSecurityMetadataSource.java:80) ~[spring-security-core-5.7.4.jar:5.7.4]
at org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource.getAttributes(DelegatingMethodSecurityMetadataSource.java:66) ~[spring-security-core-5.7.4.jar:5.7.4]
at org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor$MethodSecurityMetadataSourcePointcut.matches(MethodSecurityMetadataSourceAdvisor.java:127) ~[spring-security-core-5.7.4.jar:5.7.4]
at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:252) ~[spring-aop-5.3.23.jar:5.3.23]
at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:289) ~[spring-aop-5.3.23.jar:5.3.23]
at org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:321) ~[spring-aop-5.3.23.jar:5.3.23]
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply(AbstractAdvisorAutoProxyCreator.java:128) ~[spring-aop-5.3.23.jar:5.3.23]
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:97) ~[spring-aop-5.3.23.jar:5.3.23]
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:78) ~[spring-aop-5.3.23.jar:5.3.23]
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:341) ~[spring-aop-5.3.23.jar:5.3.23]
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:293) ~[spring-aop-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:455) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1808) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620) ~[spring-beans-5.3.23.jar:5.3.23]
... 15 common frames omitted
Caused by: org.springframework.expression.spel.SpelParseException: Expression [#{@'com.example.demo.ExampleController'.hasPermission()}] @1: EL1043E: Unexpected token. Expected 'identifier' but was 'lcurly({)'
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.internalException(InternalSpelExpressionParser.java:1041) ~[spring-expression-5.3.23.jar:5.3.23]
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.eatToken(InternalSpelExpressionParser.java:923) ~[spring-expression-5.3.23.jar:5.3.23]
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.maybeEatFunctionOrVar(InternalSpelExpressionParser.java:421) ~[spring-expression-5.3.23.jar:5.3.23]
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.eatStartNode(InternalSpelExpressionParser.java:510) ~[spring-expression-5.3.23.jar:5.3.23]
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.eatPrimaryExpression(InternalSpelExpressionParser.java:350) ~[spring-expression-5.3.23.jar:5.3.23]
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.eatUnaryExpression(InternalSpelExpressionParser.java:344) ~[spring-expression-5.3.23.jar:5.3.23]
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.eatPowerIncDecExpression(InternalSpelExpressionParser.java:303) ~[spring-expression-5.3.23.jar:5.3.23]
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.eatProductExpression(InternalSpelExpressionParser.java:281) ~[spring-expression-5.3.23.jar:5.3.23]
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.eatSumExpression(InternalSpelExpressionParser.java:263) ~[spring-expression-5.3.23.jar:5.3.23]
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.eatRelationalExpression(InternalSpelExpressionParser.java:218) ~[spring-expression-5.3.23.jar:5.3.23]
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.eatLogicalAndExpression(InternalSpelExpressionParser.java:205) ~[spring-expression-5.3.23.jar:5.3.23]
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.eatLogicalOrExpression(InternalSpelExpressionParser.java:192) ~[spring-expression-5.3.23.jar:5.3.23]
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.eatExpression(InternalSpelExpressionParser.java:153) ~[spring-expression-5.3.23.jar:5.3.23]
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.doParseExpression(InternalSpelExpressionParser.java:131) ~[spring-expression-5.3.23.jar:5.3.23]
at org.springframework.expression.spel.standard.SpelExpressionParser.doParseExpression(SpelExpressionParser.java:61) ~[spring-expression-5.3.23.jar:5.3.23]
at org.springframework.expression.spel.standard.SpelExpressionParser.doParseExpression(SpelExpressionParser.java:33) ~[spring-expression-5.3.23.jar:5.3.23]
at org.springframework.expression.common.TemplateAwareExpressionParser.parseExpression(TemplateAwareExpressionParser.java:52) ~[spring-expression-5.3.23.jar:5.3.23]
at org.springframework.expression.common.TemplateAwareExpressionParser.parseExpression(TemplateAwareExpressionParser.java:43) ~[spring-expression-5.3.23.jar:5.3.23]
at org.springframework.security.access.expression.method.ExpressionBasedAnnotationAttributeFactory.createPreInvocationAttribute(ExpressionBasedAnnotationAttributeFactory.java:53) ~[spring-security-core-5.7.4.jar:5.7.4]
... 29 common frames omitted
Даже Intellij говорит, что что-то не так:
Обновление 3 (решено)
Это работает (спасибо за @dur):
@PreAuthorize("@'com.example.demo.ExampleController'.hasPermission()")