I have controller with method that have logic for checking permission:
@RestController
@RequestMapping("/example")
public class ExampleController {
@GetMapping
@PreAuthorize("@exampleController.hasPermission()")
public String example() {
return "hello";
}
public boolean hasPermission() {
return true; // complex logic
}
}
As you can see I use SpEL to call that method (by bean name: exampleController
).
But if I change bean name generator to FullyQualifiedAnnotationBeanNameGenerator
:
@SpringBootApplication(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
now bean name is com.example.demo.ExampleController
(checked in debuger).
Following this I try to change bean name in @PreAuthorized
:
@PreAuthorize("@com.example.demo.ExampleController.hasPermission()")
but it doesn't work:
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
How to refer to bean with dots in name in SpEL? Or how to call method from controller in a different way (without using bean name)?
I know I can implement custom AnnotationBeanNameGenerator
without special characters. But I'm expecting that Spring's bean name generator is compatible with SpEL (Spring Expression Language).
Update
Answers from this and this don't work either (I guess it worked in XML config, but not in annotations):
@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()}'
Update 2
Full stack trace (for @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
Even Intellij says something is wrong:
Update 3 (resolved)
It works (thanks for @dur):
@PreAuthorize("@'com.example.demo.ExampleController'.hasPermission()")