web-dev-qa-db-ja.com

Spring Boot Securityを簡単にテストする

Spring Securityで保護されたURLのアクセス制御のテストに苦労しています。

構成は次のようになります。

    http
            .authorizeRequests()
            .antMatchers("/api/user/**", "/user").authenticated()
            .antMatchers("/api/admin/**", "/templates/admin/**", "/admin/**").hasAuthority("ADMIN")
            .anyRequest().permitAll();

そして、テストクラスは次のようになります:

package com.kubukoz.myapp;

import com.kubukoz.myapp.config.WebSecurityConfig;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import javax.transaction.Transactional;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {MyApplication.class, WebSecurityConfig.class})
@WebAppConfiguration
@TransactionConfiguration(defaultRollback = true)
@Transactional(rollbackOn = Exception.class)
public class MyApplicationTests {

    @Autowired
    private WebApplicationContext context;
    private MockMvc mockMvc;
    @Autowired
    private FilterChainProxy filterChainProxy;

    @Before
    public void setUp() {
        mockMvc = MockMvcBuilders.webAppContextSetup(context)
                .dispatchOptions(true)
                .addFilters(filterChainProxy)
                .build();
    }

    @Test
    public void testAnonymous() throws Exception {
        mockMvc.perform(get("/api/user/account")).andExpect(status().is3xxRedirection());
    }

    @Test
    public void testUserAccessForAccount() throws Exception{
        mockMvc.perform(get("/api/user/account")).andExpect(status().isOk());
    }
}

最後の2つのテストに合格する最も簡単な方法は何ですか? @WithMockUserが機能しませんでした。

11

FilterChainProxyを直接追加しないでください。代わりに、 参照 で示されるようにSecurityMockMvcConfigurers.springSecurity()を適用する必要があります。以下に例を示します。

mockMvc = MockMvcBuilders
            .webAppContextSetup(context)
            .apply(springSecurity())
            .build();

これの結果は:

  • FilterChainProxyFilterとしてMockMvcに追加されます(以前と同様)。
  • TestSecurityContextHolderPostProcessorが追加されました

なぜTestSecurityContextHolderPostProcessorが必要なのですか?その理由は、現在のユーザーをテストメソッドから作成されたMockHttpServletRequestに伝達する必要があるためです。これは、Spring SecurityのSecurityContextRepositoryFilterSecurityContextHolderの値をオーバーライドして、現在のSecurityContextRepository(つまり、SecurityContext内のHttpSession)によって検出された値になるようにするために必要です。

更新

メソッド名にroleを含むものはすべて、渡された文字列の前に「ROLE_」が自動的に付加されます。

コメントに基づいて、問題はhasAuthorityの代わりにhasRoleを使用するように構成を更新する必要があることです(注釈がロールを使用しているため)。

.authorizeRequests()
            .antMatchers("/api/user/**", "/user").authenticated()
            .antMatchers("/api/admin/**", "/templates/admin/**", "/admin/**").hasRole("ADMIN")
            .anyRequest().permitAll();

または

Spring Security 4.0.2+では、以下を使用できます。

@WithMockUser(authorities="ADMIN")
16
Rob Winch

わかりました。

mockMvc.perform(get("/api/user/account")
      .with(user("user")))
      .andExpect(status().isOk());

それは今動作します。

1