【问题标题】:How do I unit test spring security @PreAuthorize custom expression如何对 Spring Security @PreAuthorize 自定义表达式进行单元测试
【发布时间】:2020-10-08 09:37:19
【问题描述】:
    @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)
    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

如何使表达式解析 bean?

使用 @MockBean MessageSecurityService 不起作用。

【问题讨论】:

    标签: java unit-testing spring-security javabeans spring-expression-language


    【解决方案1】:

    您是否对@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);
    }
    

    【讨论】:

    • 是的,谢谢你成功了。 @MockBean (name = "message Security Service") 足以做到这一点。在不添加 MockitoAnnotations.initMocks (this) 的情况下工作。
    • 我们添加了在测试运行时将所有模拟对象一起初始化的设置方法。使用 @BeforeEach 注释的方法在每个测试方法之前运行。 init() 方法使用此实例作为参数运行 MockitoAnnotations.initMocks(this)。这会在每次测试之前设置我们的模拟
    • 由于我的测试使用 SpringRunner 运行,它设置了模拟,而不需要 initMocks 已经在其内部执行此操作。 /** * 构造一个新的 {@code SpringRunner} 并初始化一个 * {@link org.springframework.test.context.TestContextManager TestContextManager} * 为标准 JUnit 4 测试提供 Spring 测试功能。
    • 为什么mockbean注解要名字bean作为参数进去呢?如果不写 Bean 的名字,测试就无法进行。
    猜你喜欢
    • 2014-04-27
    • 2015-01-01
    • 2018-05-27
    • 1970-01-01
    • 1970-01-01
    • 2015-02-16
    • 2018-09-19
    • 2018-04-26
    • 2018-10-07
    相关资源
    最近更新 更多