首页 > 解决方案 > SpringBoot Rest Controller集成测试总是给401未授权

问题描述

我有一个休息控制器,它有简单的 CRUD 操作。我正在尝试编写集成测试。

下面是我的 RestController:

package com.gasx.corex.scheduler.controller;

import java.awt.*;
import java.util.List;

import com.gasx.corex.scheduler.service.SchedulerJobServiceI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.gasx.corex.ext.scheduler.domain.SchedulerJob;
import com.gasx.corex.scheduler.service.SchedulerJobService;


@RestController
@RequestMapping("/gasx/restscd")
public class SchedulerJobController {

    @Autowired
    private SchedulerJobServiceI schedulerJobService;

    @RequestMapping(method = RequestMethod.GET , path="/getschedulerjobs" , produces= MediaType.APPLICATION_JSON_VALUE)
    public List<SchedulerJob> getAllSchedulerJobs() {
        return schedulerJobService.getAllSchedulerJobs();
    }

    @RequestMapping(method = RequestMethod.POST, value = "/addschedulerjob")
    public void addSchedulerJob(@RequestBody SchedulerJob schedulerJob) {
        schedulerJobService.addSchedulerJob(schedulerJob);
    }

    @RequestMapping(method = RequestMethod.POST, value = "/updateschedulerjob")
    public void updateSchedulerJob(@RequestBody SchedulerJob schedulerJob) {
        schedulerJobService.updateSchedulerJob(schedulerJob);
    }

    @RequestMapping(method = RequestMethod.POST, value = "/deleteschedulerjob")
    public void deleteSchedulerJob(@RequestBody SchedulerJob schedulerJob) {
        schedulerJobService.deleteSchedulerJob(schedulerJob);
    }
}

我已经为 RestController 中的所有端点编写了集成测试

集成测试类:-

package com.gasx.corex.ext.scheduler.integrationtest.domain;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gasx.corex.base.configuration.CoreConfiguration;
import com.gasx.corex.ext.scheduler.domain.SchedulerJob;
import com.gasx.corex.ext.scheduler.domain.utils.SchedulerJobType;


import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.http.HttpHeaders;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.WebApplicationContext;
import sun.security.krb5.internal.Ticket;
import org.springframework.http.HttpMethod;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;

import java.io.IOException;
import java.util.Base64;

import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT  , properties = {
        "management.server.port=0", "management.context-path=/admin" ,"security.basic.enabled=false"} )
@EnableAutoConfiguration
@ContextConfiguration( classes = {CoreConfiguration.class  } )
@AutoConfigureMockMvc
public class SchedulerJobTestInt {

    @LocalServerPort
    private int port  ;


    @Autowired
    private TestRestTemplate testRestTemplate;

    @Autowired
    WebApplicationContext context;

    @Autowired
    private MockMvc mockMvc;


    @Before
    public void setUp() {
        this.mockMvc = MockMvcBuilders
                .webAppContextSetup(context)
                .build();
    }

    @Test
    public void getAllSchedulerJobsIntTest() throws Exception {
        ResponseEntity<String> response = testRestTemplate.getForEntity("http://localhost:" + port +"/gasx/restscd/getschedulerjobs", String.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);

        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode responseJson = objectMapper.readTree(response.getBody());

        assertThat(responseJson.isMissingNode()).isFalse();
        assertThat(responseJson.toString()).isEqualTo("[]");
    }




    @Test
    public void addSchedulerJobIntTest() throws  Exception{
        SchedulerJob schedulerJob = new SchedulerJob();
        schedulerJob.setName("ALB Cleanup");
        schedulerJob.setDescription("Cleanup of alb jobs. Please do not deactivate!");
        schedulerJob.setType(SchedulerJobType.REST);
        schedulerJob.setActive(true);
        schedulerJob.setStartMissedRun(false);
        schedulerJob.setCategory("SYSTEM");
        schedulerJob.setCronExpression(null);
        schedulerJob.setScheme("testScheme");
        schedulerJob.setIdRegion(1);
        schedulerJob.setAlbEndpoint("testAlbEndPoint");
        schedulerJob.setAlbPayload("SCHED_ALB");
        schedulerJob.setAlbPrio(1);
        schedulerJob.setAlbJobUser("MKRAUS");
        schedulerJob.setScriptParams("testScriptParams");
        schedulerJob.setShellScriptParams("clear_tmp 15");
        schedulerJob.setSoapEndpointAlias("");
        schedulerJob.setSoapImportPath("CORE/CORE2003/imp/price");
        schedulerJob.setSoapExportPath("testExportPath");
        schedulerJob.setSoapPayload("<api:readPartnersByIdRequest>");
        schedulerJob.setSoapAction("urn:readPartnersById");
        schedulerJob.setRestEndpointAlias("testEndpointAlias");
        schedulerJob.setRestUrl("testUrl");
        schedulerJob.setRestEntityContent("");
        schedulerJob.setRestExportPath("testRestExportPath");
        schedulerJob.setHookScriptName("testHookScriptName");
        schedulerJob.setMinutes("");
        schedulerJob.setHours("");






        String plainCredentials="gasx:gasx!";
        String base64Credentials = Base64.getEncoder().encodeToString(plainCredentials.getBytes());
        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization", "Basic " + base64Credentials);
        headers.add("Accept" , "application/json");


        HttpEntity<String> entity = new HttpEntity<String>(asJsonString(schedulerJob), headers);


        //    ResponseEntity<Void> response = testRestTemplate.postForEntity("http://localhost:"+port +"/gasx/restscd/addschedulerjob", entity,Void.class);
        ResponseEntity<Void> response = testRestTemplate.postForEntity("http://localhost:" + port +"/gasx/restscd/addschedulerjob", asJsonString(schedulerJob),Void.class);
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);

    }

    private String createURLWithPort(String uri) {
        return "http://localhost:" + port + uri;
    }

    @Test
    public void updateSchedulerJobTest(){
        SchedulerJob schedulerJob = new SchedulerJob();
        schedulerJob.setName("ALB Cleanup");
        schedulerJob.setDescription("Cleanup of alb jobs. Please do not deactivate!");
        schedulerJob.setType(SchedulerJobType.REST);
        schedulerJob.setActive(true);
        schedulerJob.setStartMissedRun(false);
        schedulerJob.setCategory("SYSTEM");
        schedulerJob.setCronExpression(null);
        schedulerJob.setScheme("testScheme");
        schedulerJob.setIdRegion(1);
        schedulerJob.setAlbEndpoint("testAlbEndPoint");
        schedulerJob.setAlbPayload("SCHED_ALB");
        schedulerJob.setAlbPrio(1);
        schedulerJob.setAlbJobUser("MKRAUS");
        schedulerJob.setScriptParams("testScriptParams");
        schedulerJob.setShellScriptParams("clear_tmp 15");
        schedulerJob.setSoapEndpointAlias("");
        schedulerJob.setSoapImportPath("CORE/CORE2003/imp/price");
        schedulerJob.setSoapExportPath("testExportPath");
        schedulerJob.setSoapPayload("<api:readPartnersByIdRequest>");
        schedulerJob.setSoapAction("urn:readPartnersById");
        schedulerJob.setRestEndpointAlias("testEndpointAlias");
        schedulerJob.setRestUrl("testUrl");
        schedulerJob.setRestEntityContent("");
        schedulerJob.setRestExportPath("testRestExportPath");
        schedulerJob.setHookScriptName("testHookScriptName");
        schedulerJob.setMinutes("");
        schedulerJob.setHours("");

        ResponseEntity<Void> response = testRestTemplate.withBasicAuth("gasx" ,"gasx!").postForEntity("http://localhost:" + port +"/gasx/restscd/updateschedulerjob", schedulerJob,Void.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);

    }

    @Test
    public void deleteSchedulerJob(){

        SchedulerJob schedulerJob = new SchedulerJob();
        schedulerJob.setName("ALB Cleanup");
        schedulerJob.setDescription("Cleanup of alb jobs. Please do not deactivate!");
        schedulerJob.setType(SchedulerJobType.REST);
        schedulerJob.setActive(true);
        schedulerJob.setStartMissedRun(false);
        schedulerJob.setCategory("SYSTEM");
        schedulerJob.setCronExpression(null);
        schedulerJob.setScheme("testScheme");
        schedulerJob.setIdRegion(1);
        schedulerJob.setAlbEndpoint("testAlbEndPoint");
        schedulerJob.setAlbPayload("SCHED_ALB");
        schedulerJob.setAlbPrio(1);
        schedulerJob.setAlbJobUser("MKRAUS");
        schedulerJob.setScriptParams("testScriptParams");
        schedulerJob.setShellScriptParams("clear_tmp 15");
        schedulerJob.setSoapEndpointAlias("");
        schedulerJob.setSoapImportPath("CORE/CORE2003/imp/price");
        schedulerJob.setSoapExportPath("testExportPath");
        schedulerJob.setSoapPayload("<api:readPartnersByIdRequest>");
        schedulerJob.setSoapAction("urn:readPartnersById");
        schedulerJob.setRestEndpointAlias("testEndpointAlias");
        schedulerJob.setRestUrl("testUrl");
        schedulerJob.setRestEntityContent("");
        schedulerJob.setRestExportPath("testRestExportPath");
        schedulerJob.setHookScriptName("testHookScriptName");
        schedulerJob.setMinutes("");
        schedulerJob.setHours("");

        ResponseEntity<Void> response = testRestTemplate.withBasicAuth("gasx" ,"gasx!").postForEntity("http://localhost:" + port +"/gasx/restscd/deleteschedulerjob", schedulerJob,Void.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);


    }


    public static String asJsonString(final Object obj) {
        try {
            return new ObjectMapper().writeValueAsString(obj);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

我的问题:

1.)每当我在 Rest Controller 中放置断点时,它都不会停在那里,实际上它没有被调用。

2.)当我运​​行 GET 测试时,它会从 response.getBody() 返回登录 html 页面

3.)当我运​​行 POST 测试时,它返回状态 401 未授权

在谷歌上尝试了许多可能的解决方案,甚至通过评论配置禁用了 Spring Security,但它仍然不起作用。

我可以从我的单元测试中调用相同的 Rest Controller 并且可以停止断点。

我的安全配置:-

package com.gasx.corex.scheduler.server;

import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;

import com.gasx.corex.ext.user.domain.DefaultRoles;

@Configuration
@EnableWebSecurity
@Order(1)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        // @formatter:off
        httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
            .httpBasic().and()
            .authorizeRequests()
                .antMatchers("/gasx/**").hasAnyAuthority(DefaultRoles.ROOT.getName(), DefaultRoles.ADMIN.getName(), DefaultRoles.ACTUATOR.getName())
                .antMatchers("/webjars/**").hasAnyAuthority(DefaultRoles.ROOT.getName(), DefaultRoles.ADMIN.getName(), DefaultRoles.ACTUATOR.getName())
                .antMatchers("/monitor/**").hasAnyAuthority(DefaultRoles.ROOT.getName(), DefaultRoles.ACTUATOR.getName())
                // dev urls
                .antMatchers("/h2-console/**").hasAuthority(DefaultRoles.ROOT.getName())
                .antMatchers("/swagger*/**","/v2/**").hasAnyAuthority(DefaultRoles.ROOT.getName(), DefaultRoles.ADMIN.getName())
                .anyRequest().denyAll();
        // @formatter:on

        httpSecurity.csrf().disable();
        httpSecurity.headers().frameOptions().disable();
    }
}

又尝试了一件事,在我的包中添加了以下类:-

package com.gasx.corex.ext.scheduler.integrationtest.domain;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class AllowAnonymousWebAccess extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(HttpSecurity web) throws Exception {
        web.antMatcher("**/*").anonymous();
    }
}

现在它给出了404。

标签: javaspring-bootjunitintegration-testing

解决方案


我对这个项目的 SecurityConfiguration 一无所知(你应该提供一些关于它的更多信息),但我认为你应该提供一些授权数据(比如 Authorization 标头中的 JWT,等等)

你能给我更多关于 SecurityConfig 的信息吗?(寻找org.springframework.security.config.something.something...进口)

编辑

我看了你的代码,实际上这部分

    httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
        .httpBasic().and()
        .authorizeRequests()
            .antMatchers("/gasx/**").hasAnyAuthority(DefaultRoles.ROOT.getName(), DefaultRoles.ADMIN.getName(), DefaultRoles.ACTUATOR.getName())

使用 httpBasic 类型授权保护您的 API。您应在标头中提供凭据以测试您的应用程序。


推荐阅读