Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/389.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MockMvc在执行请求后似乎是清晰的SecurityContext(java.lang.IllegalArgumentException:Authentication对象不能为null)_Java_Spring_Spring Data_Spring Data Mongodb_Mockmvc - Fatal编程技术网

MockMvc在执行请求后似乎是清晰的SecurityContext(java.lang.IllegalArgumentException:Authentication对象不能为null)

MockMvc在执行请求后似乎是清晰的SecurityContext(java.lang.IllegalArgumentException:Authentication对象不能为null),java,spring,spring-data,spring-data-mongodb,mockmvc,Java,Spring,Spring Data,Spring Data Mongodb,Mockmvc,我正在尝试使用SpringBoot+SpringDataMongo+SpringMVC运行一些集成测试 我已经简化并泛化了代码,但是它应该能够通过下面的测试重现行为 从BookRepository界面可以看到,我希望用户能够只检索他拥有的书籍(@Query(“{ownerName:”?#{principal?.username})),我正在编写一个测试,以执行POST来保存一本书,然后验证该书是否正确设置了所有者 为了回答这里的问题,我将测试简化为一个GET,然后调用findAll() 问题 在

我正在尝试使用SpringBoot+SpringDataMongo+SpringMVC运行一些集成测试

我已经简化并泛化了代码,但是它应该能够通过下面的测试重现行为

BookRepository
界面可以看到,我希望用户能够只检索他拥有的书籍(
@Query(“{ownerName:”?#{principal?.username})
),我正在编写一个测试,以执行
POST
来保存一本书,然后验证该书是否正确设置了所有者

为了回答这里的问题,我将测试简化为一个
GET
,然后调用
findAll()

问题 在执行任何
MockMvc
请求后,使用
ThreadLocalSecurityContextHolderStrategy\35; clearContext()
清除
SecurityContext
,这会导致在我尝试调用
repository.findAll();

java.lang.IllegalArgumentException:身份验证对象不能为null

BookRepository.java
我认为您可以手动配置
MockMvc
并如下配置Spring安全性,而不是使用
AutoConfigureMockMvc
注释:

import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*;

@RunWith(SpringRunner.class)
@SpringBootTest
public class BookCustomRepositoryIntegrationTest {

    @Before
    public void setup() {
        mockMvc = MockMvcBuilders
                .webAppContextSetup(context)
                .apply(springSecurity()) 1
                .build();
    }
    // ...
}
作为缔约国:

为了在Spring MVC测试中使用Spring Security,有必要添加Spring Security FilterChainProxy作为过滤器。还需要添加Spring Security的TestSecurityContextHolderPostProcessor,以支持在带有注释的Spring MVC测试中以用户身份运行。这可以使用Spring Security的SecurityLockMVCConfigure完成rs.springSecurity()


您的案例不起作用,因为SecurityContextPersistenceFilter和FilterChainProxy筛选器清除了SecurityContextHolder,但
TestSecurityContextHolder
(由
用SecurityContextTestExecutionListener填写)仍然包含SecurityContext

尝试以下方法:

@Test
@WithMockUser
public void reproduceBug() throws Exception {
    repository.findAll();
    mockMvc.perform(get("/books")
            .contentType(APPLICATION_JSON_UTF8))
            .andExpect(status().isOk());
    SecurityContextHolder.setContext(TestSecurityContextHolder.getContext());
    repository.findAll();
}

您可能忘记用
@controller
注释标记任何控制器。在我的情况下发生了这种情况,修复它有助于修复错误。这可能是故障排除步骤之一

发生这种情况的原因是,当您在运行时不使用
@controller
标记控制器并尝试从模板语言(在我的例子中是Thymeleaf)进行引用时,它会在上下文中向下延伸并返回丢失身份验证对象,因此会出现如下错误:

Caused by: org.attoparser.ParseException: Exception evaluating SpringEL expression: "#authorization.expression('!isAuthenticated()')" (template: "fragments/layout" - line 64, col 8)
    at org.attoparser.MarkupParser.parseDocument(MarkupParser.java:393)
    at org.attoparser.MarkupParser.parse(MarkupParser.java:257)
    at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:230)
    ... 47 more
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "#authorization.expression('!isAuthenticated()')" (template: "fragments/layout" - line 64, col 8)
    at org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:290)
...
...
...
...
... 49 more
Caused by: java.lang.IllegalArgumentException: Authentication object cannot be null
    at org.springframework.security.access.expression.SecurityExpressionRoot.<init>(SecurityExpressionRoot.java:61)
原因:org.attoparser.ParseException:异常评估SpringEL表达式:“#authorization.expression(“!isAuthenticated()”)”(模板:“片段/布局”-第64行,第8列)
位于org.attoparser.MarkupParser.parseDocument(MarkupParser.java:393)
位于org.attoparser.MarkupParser.parse(MarkupParser.java:257)
位于org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:230)
…还有47个
原因:org.thymeleaf.exceptions.TemplateProcessingException:异常评估SpringEL表达式:“#authorization.expression(“!isAuthenticated()”)”(模板:“片段/布局”-第64行,第8列)
位于org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:290)
...
...
...
...
…还有49个
原因:java.lang.IllegalArgumentException:身份验证对象不能为null
位于org.springframework.security.access.expression.SecurityExpressionRoot.(SecurityExpressionRoot.java:61)

希望这有帮助。

我刚刚找到了一个很好的解决方案。您可以在测试配置中注册一个MockMvcBuilderCustomizer bean,一切正常

public class MockMvcTestSecurityContextPropagationCustomizer implements MockMvcBuilderCustomizer {

@Override
public void customize(ConfigurableMockMvcBuilder<?> builder) {
    builder.alwaysDo(result -> {
        log.debug("resetting SecurityContextHolder to TestSecurityContextHolder");
        SecurityContextHolder.setContext(TestSecurityContextHolder.getContext());
    });
}
公共类MockMvcTestSecurityContextPropagationCustomizer实现MockMvcBuilderCustomizer{
@凌驾
public void自定义(ConfigurableMockMvcBuilder builder){
builder.alwaysDo(结果->{
调试(“将SecurityContextHolder重置为TestSecurityContextHolder”);
setContext(TestSecurityContextHolder.getContext());
});
}
}


[spring boot]

整个安全过滤器链都在那里,事实上,当我调用repository.findAll()时,身份验证上下文就在那里.但是MockMvc出于某种原因清理了它,这使得一个完全合理的测试用例无法执行。无论如何,我尝试了你的方法,但我得到了相同的错误。非常感谢你尝试帮助hi@seregamorph,而不是你的建议。这是我迄今为止看到的最好的解决方法,所以我将投票支持它。但是,我不相信manuaLLY在与MockMvc进行交互后设置安全上下文,这是一个非常可读的测试,所以我不认为它是一个明确的解决方案。
Caused by: org.attoparser.ParseException: Exception evaluating SpringEL expression: "#authorization.expression('!isAuthenticated()')" (template: "fragments/layout" - line 64, col 8)
    at org.attoparser.MarkupParser.parseDocument(MarkupParser.java:393)
    at org.attoparser.MarkupParser.parse(MarkupParser.java:257)
    at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:230)
    ... 47 more
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "#authorization.expression('!isAuthenticated()')" (template: "fragments/layout" - line 64, col 8)
    at org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:290)
...
...
...
...
... 49 more
Caused by: java.lang.IllegalArgumentException: Authentication object cannot be null
    at org.springframework.security.access.expression.SecurityExpressionRoot.<init>(SecurityExpressionRoot.java:61)
public class MockMvcTestSecurityContextPropagationCustomizer implements MockMvcBuilderCustomizer {

@Override
public void customize(ConfigurableMockMvcBuilder<?> builder) {
    builder.alwaysDo(result -> {
        log.debug("resetting SecurityContextHolder to TestSecurityContextHolder");
        SecurityContextHolder.setContext(TestSecurityContextHolder.getContext());
    });
}