Spring Security + Spring-Boot Testing Controller

2019-07-21 13:03发布

问题:

I'm trying to test the home controller

@RequestMapping("/")
@ResponseBody
String home() {
    return "Hello World!";
}

I'm using spring security using as username "user" and test as password by default but @PreAuthorize is not working

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@PreAuthorize("hasRole('ADMIN')")
public class HomeControllerTest {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    @WithMockUser(username = "user", password = "test", roles = "ADMIN")
    public void home() throws Exception {
        String body = this.restTemplate.getForObject("/", String.class);
        assertThat(body).isEqualTo("Hello World!");
    }

}

The result

Expected result:

<"[Hello World!]">

Actual result:

<"{"timestamp":1501100448216,"status":401,"error":"Unauthorized","message":"Full authentication is required to access this resource","path":"/"}]">

Am I missing something?

回答1:

Try to add the following to your test class:

@TestExecutionListeners(mergeMode = MergeMode.MERGE_WITH_DEFAULTS, listeners = {
        WithSecurityContextTestExecutionListener.class
})

And the following dependency if you don't have it:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <scope>test</scope>
</dependency>

Spring security require an extra listener that is not present in tests by default so you need to tell spring to add it by specifing the @TestExecutionListeners annotation in merge mode so it will merge the current listed listeners with the listeners you want to add - in this case WithSecurityContextTestExecutionListener



回答2:

You used invaild password, because

The default AuthenticationManager has a single user (‘user’ username and random password, printed at INFO level when the application starts up) doc

You can create custom user and do test againe

@Bean
public UserDetailsService userDetailsService() throws Exception {
    InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
    manager.createUser(User.withUsername("admin").password("passAdmin").roles("USER", "ADMIN").build());
    return manager;
}