簡體   English   中英

使用 MockMvc 測試 spring 安全性時未調用自定義身份驗證提供程序

[英]Custom Authentication Provider not called when testing spring security with MockMvc

我正在嘗試使用 spring 的 MockMvc 類在我的 spring boot 應用程序中測試我的 spring OAuth2 授權和身份驗證。 我面臨的根本問題是,即使我已將其注冊為 spring security 使用的身份驗證提供程序之一,我的自定義身份驗證提供程序也永遠不會被調用。 我遵循了此處此處的 spring 安全教程。

代碼片段:安全配置器類 - 這是添加自定義身份驗證提供程序的地方。

@Configuration
@EnableWebSecurity
public class SecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Autowired
    private AuthenticationProvider authenticationProvider;


    @Override
    public void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(authenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .httpBasic();
    }
}

自定義身份驗證提供程序 - 這應該進行實際的身份驗證

@Component
public class UsernamePasswordAuthProvider implements AuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = authentication.getCredentials()
                .toString();

        if ("test".equals(username) && "test".equals(password)) {
            Collection<? extends GrantedAuthority> grantedAuthorityList = authentication
                    .getAuthorities();
            return new UsernamePasswordAuthenticationToken
                    (username, password, grantedAuthorityList);
        } else {
            throw new
                    BadCredentialsException("External system authentication failed");
        }
    }

    @Override
    public boolean supports(Class<?> auth) {
        return true;
    }
}

Spring Boot 集成測試——這是使用 Web 應用程序上下文實例化 MockMvc 的地方

@RunWith(SpringRunner.class)
@SpringBootTest(classes = ConfigurationServiceApplication.class)
public class SettingsAPITest {

    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext wac;

    @Autowired
    private FilterChainProxy springSecurityFilterChain;


    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
                .addFilter(springSecurityFilterChain).build();
    }


    @Test 
    public void testGetStatus() throws Exception {
        //execute test
        mockMvc.perform(get("/status")
                .with(httpBasic("test","test")))
                .andDo(print())
                .andExpect(status().isOk());
    }
}

這是控制器

@RestController
public class StatusController{

    @RequestMapping(method = RequestMethod.GET)
    public ResponseEntity<String> getStatus(){

        return new ResponseEntity<>("I'm Ok", HttpStatus.OK);

    }
}

運行測試返回 401 並放置一個斷點並通過它進行調試表明從未使用過自定義身份驗證提供程序。

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /status
       Parameters = {}
          Headers = {Authorization=[Basic dGVzdDp0ZXN0]}

Handler:
             Type = null

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 401
    Error message = null
          Headers = {X-Content-Type-Options=[nosniff], X-XSS-Protection=[1; mode=block], Cache-Control=[no-cache, no-store, max-age=0, must-revalidate, no-store], Pragma=[no-cache, no-cache], Expires=[0], X-Frame-Options=[DENY], WWW-Authenticate=[Bearer realm="oauth2-resource", error="unauthorized", error_description="Full authentication is required to access this resource"], Content-Type=[application/json;charset=UTF-8]}
     Content type = application/json;charset=UTF-8
             Body = {"error":"unauthorized","error_description":"Full authentication is required to access this resource"}
    Forwarded URL = null    Redirected URL = null
          Cookies = []

java.lang.AssertionError: Status  Expected :200 Actual   :401

我有一種感覺,我的 webapp 上下文配置在某個地方被 spring boot 覆蓋了(因為這里的大部分內容都是由 spring boot 自動配置的),但我無法證明這一點。 非常感謝任何幫助! 謝謝

僅供參考,我看過相關帖子

我使用教程來設置身份驗證提供程序。 為了測試,這是我的設置:

import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.client.RestTemplate;

@RunWith(SpringRunner.class)
@WebMvcTest(MyController.class)
public class MyControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private RestTemplate restTemplate;


    @TestConfiguration
    static class AdditionalConfig {

        @Bean
        public MyAuthenticationProvider productValidator() {
            return new MyAuthenticationProvider();
        }

    }

    @Test
    public void shouldGetDocuments() throws Exception {
        this.mockMvc.perform(post("/partners/links/")
            .with(httpBasic("user", "password")))
                    .andExpect(status().isOk())
                    .andReturn();
    }
}

請記住,如果您忘記在測試中提供憑據(在我的例子中是基本身份驗證),您的自定義身份驗證提供程序將不會被調用。

要模擬AuthenticationProvider ,請在#RequestBuilder中使用您的授權模型。 例如, SecurityMockMvcRequestPostProcessors.httpBasic()

此外,如果您的授權需要標頭,您可以添加它們。

@Test
fun `when authenticated user requests a secure endpoint, then success`() {
    val requestBuilder = MockMvcRequestBuilders
            .get(provideFullUrl(SecurityCoreEndpointsTest.Keys.SECURE))
            .with(httpBasic("your-username", "your-password"))
                    .header("Header-Key", "Value")  

    val resultMatcher = MockMvcResultMatchers.status().isOk

    mockMvc.perform(requestBuilder).andExpect(resultMatcher)
}

注意:使用@WithMockUser對我不起作用

GL

你能嘗試改變你的 mockmvc 初始化嗎

@Before
public void setup() {
    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
            .addFilter(springSecurityFilterChain).build();
}

@Before
public void setup() {
    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
            .apply(springSecurity()).build();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM