如何对Spring Security中的@PreAuthorize自定义表达式进行单元测试。

huangapple go评论81阅读模式
英文:

How do I unit test spring security @PreAuthorize custom expression

问题

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
@PreAuthorize("@messageSecurityService.isAuthorized(#userAuthentication)")
public void sendMessage(@AuthenticationPrincipal UserAuthentication userAuthentication,
                        @RequestBody SendMessageRequest sendMessageRequest) {
    // ......
}
java.lang.IllegalArgumentException: Failed to evaluate expression '@messageSecurityService.isAuthorized(#userAuthentication)'
    at org.springframework.security.access.expression.ExpressionUtils.evaluateAsBoolean(ExpressionUtils.java:30)
    at org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice.before(ExpressionBasedPreInvocationAdvice.java:59)
    // ... (more stack trace)
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1058E: A problem occurred when trying to resolve bean 'messageSecurityService':'Could not resolve bean reference against BeanFactory'
    at org.springframework.expression.spel.ast.BeanReference.getValueInternal(BeanReference.java:59)
    // ... (more stack trace)
Caused by: org.springframework.expression.AccessException: Could not resolve bean reference against BeanFactory
    at org.springframework.context.expression.BeanFactoryResolver.resolve(BeanFactoryResolver.java:54)
    // ... (more stack trace)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'messageSecurityService' available
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:775)
    // ... (more stack trace)

To make the expression resolve the bean:

  1. Ensure that you have a Spring bean named 'messageSecurityService' registered in your application context.
  2. Make sure that the bean is properly configured and initialized.
  3. Confirm that the bean's name matches exactly with the one used in the @PreAuthorize expression (@messageSecurityService).
  4. If you are writing a unit test, you can use the @MockBean annotation to mock the MessageSecurityService bean. Make sure to properly configure the mock's behavior in your test.

Example usage of @MockBean in a test class:

@RunWith(SpringRunner.class)
@WebMvcTest(YourController.class)
public class YourControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private MessageSecurityService messageSecurityService;

    // ... your test methods
}

Make sure to configure the behavior of the messageSecurityService mock in your test methods according to your test scenarios.

英文:
    @PostMapping
        @ResponseStatus(HttpStatus.CREATED)
        @PreAuthorize("@messageSecurityService.isAuthorized(#userAuthentication)")
        public void sendMessage(@AuthenticationPrincipal UserAuthentication userAuthentication,
                                @RequestBody SendMessageRequest sendMessageRequest) {
                                              ......
     }

I want to write the test of this endpoint, but I am getting the following error.

 java.lang.IllegalArgumentException: Failed to evaluate expression '@messageSecurityService.isAuthorized(#userAuthentication)'
	at org.springframework.security.access.expression.ExpressionUtils.evaluateAsBoolean(ExpressionUtils.java:30)
	at org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice.before(ExpressionBasedPreInvocationAdvice.java:59)
	at org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter.vote(PreInvocationAuthorizationAdviceVoter.java:72)
	at org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter.vote(PreInvocationAuthorizationAdviceVoter.java:40)
	at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:63)
	at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233)
	at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:65)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)

Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1058E: A problem occurred when trying to resolve bean 'messageSecurityService':'Could not resolve bean reference against BeanFactory'
	at org.springframework.expression.spel.ast.BeanReference.getValueInternal(BeanReference.java:59)
	at org.springframework.expression.spel.ast.CompoundExpression.getValueRef(CompoundExpression.java:53)
	at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:89)
	at org.springframework.expression.spel.ast.SpelNodeImpl.getTypedValue(SpelNodeImpl.java:114)
	at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:300)
	at org.springframework.security.access.expression.ExpressionUtils.evaluateAsBoolean(ExpressionUtils.java:26)
	... 94 common frames omitted

Caused by: org.springframework.expression.AccessException: Could not resolve bean reference against BeanFactory
	at org.springframework.context.expression.BeanFactoryResolver.resolve(BeanFactoryResolver.java:54)
	at org.springframework.expression.spel.ast.BeanReference.getValueInternal(BeanReference.java:55)
	... 99 common frames omitted

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'messageSecurityService' available
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:775)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1221)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:294)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:273)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1105)
	at org.springframework.context.expression.BeanFactoryResolver.resolve(BeanFactoryResolver.java:51)
	... 100 common frames omitted

How can I make the expression resolve bean ?

Using
@MockBean
MessageSecurityService didn't work.

答案1

得分: 2

你是否已经对 @MockBean 的返回进行了桩设,例如:

@MockBean(name = "messageSecurityService")
public MessageSecurityService messageSecurityService;

@Test
public void testing(){
 when(messageSecurityService.isAuthorized(anyString())).thenReturn("somethingHere");
 //rest of your assertions
}

同时,你是否在测试类中添加了以下内容:

@BeforeEach
public void init() {
    MockitoAnnotations.initMocks(this);
}
英文:

Have you stub the return of the @MockBean e.g

@MockBean(name = "messageSecurityService")
public MessageSecurityService messageSecurityService;

@Test
public void testing(){
 when(messageSecurityService.isAuthorized(anyString())).thenReturn("somethingHere");
 //rest of your assertions
}

also have you added the following in your test class:

@BeforeEach
public void init() {
    MockitoAnnotations.initMocks(this);
}

huangapple
  • 本文由 发表于 2020年10月8日 17:37:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/64259736.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定