【问题标题】:Springboot Junit Test expect 200 but getting 403 forbiddenSpringboot Junit 测试期望 200 但禁止 403
【发布时间】:2019-12-02 12:35:38
【问题描述】:

我正在 Junit 测试一个控制器,该控制器使用 JPA 存储库作为数据库。我的内存数据库中的 H2 工作正常,我的 GET 请求映射按预期工作。我的 PUT 得到 403,而我期望得到 200。我已经尝试了各种不同的配置,使用 AutoConfigureMockMvc 和安全错误,并且不包括安全自动配置。

关于 PUT 请求、安全配置或需要围绕令牌添加配置,我是否遗漏了什么?

这是我的 Junit 测试,saveTest 正常工作,而 updateTest 返回 403。

@EnableAutoConfiguration(exclude = SecurityAutoConfiguration.class)


@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc(secure = false) 
@Import(SecurityConfig.class)

@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class DBcontroltest {



@Autowired
DbRequest dbRequest;


    @Autowired
    ConnectionRequestRepository connectionRequestRepository;

    @Autowired
    private MockMvc mockMvc;
    private String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
    private Date date;
    private String dateFormatted = "2019-11-26T14:33:13.175+0000";

    {
        try {
            date = simpleDateFormat.parse("2019-11-26T14:33:13.175+0000");
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

        @Test
    public void saveTest() throws Exception {
        ConnectionRequest connectionRequest = new ConnectionRequest((long) 1, "bleep", "market", "dev", "conn1", "fun", "java", "styff", "hello", "whoop", date, "dldl");
        connectionRequestRepository.save(connectionRequest);

        String body = "{\"connectionId\":1,\"requestor\":\"bleep\",\"market\":\"market\",\"platform\":\"dev\",\"environment\":\"conn1\",\"connectionName\":\"fun\",\"connectionType\":\"java\",\"databaseId\":\"styff\",\"databasePwd\":\"hello\",\"email\":\"whoop\",\"requestDate\":\"" + dateFormatted + "\",\"jobStatus\":\"dldl\"}\n" +
                 " ";
         mockMvc.perform(get("/api/selectDB/{connectionId}" ,1))
                 .andExpect(content().json(body))
           .andExpect(status().isOk());


    }


 @Test
    public void updateTest() throws Exception {

        ConnectionRequest connectionRequest = new ConnectionRequest((long) 1, "bleep", "market", "dev", "conn1", "connname", "java", "db", "hello", "email@aol.com", date, "done");
        connectionRequestRepository.save(connectionRequest);


        String body3 = "{\"requestor\":\"NEWGUY\"}";
        MockHttpServletRequestBuilder builder =
                MockMvcRequestBuilders.put("/api/updateDB/{connectionId}" ,1)
                        .contentType("application/json")
                        .content(body3);
        System.out.println(connectionRequestRepository.findById((long) 1));
        this.mockMvc.perform(builder)
                .andExpect(MockMvcResultMatchers.status()
                        .isOk())
                .andDo(MockMvcResultHandlers.print());
        System.out.println(connectionRequestRepository.findById((long) 1));

    }
}

这是我的控制器,

@Data
@RestController
@RequestMapping("/api/")
public class DbRequest {

    @Autowired
    private ConnectionRequestRepository connectionRequestRepository;
    private ConnectionRequest connectionRequest;


    @GetMapping("/selectDB/{connectionId}")
    public ResponseEntity<ConnectionRequest> getRequestById(@PathVariable("connectionId") Long connectionId) throws Exception {
        ConnectionRequest connectionRequest = connectionRequestRepository.findById(connectionId)
            .orElseThrow(() -> new Exception("Connection Request " + connectionId + " not found"));
        return ResponseEntity.ok().body(connectionRequest);
    }

    @PutMapping("/updateDB/{connectionId}")
    public ResponseEntity<ConnectionRequest> updateConnectionRequest(@PathVariable("connectionId") Long connectionId,
                                                                     @Valid @RequestBody ConnectionRequest connectionRequestDetails) throws Exception {
        long completedDateTime = System.currentTimeMillis();
        System.out.println("completeDateTime is " + completedDateTime);

        ConnectionRequest connectionRequest = connectionRequestRepository.findById(connectionId)
            .orElseThrow(() -> new Exception("Connection Request " + connectionId + " not found"));
        System.out.println("value for connectionrequest is " + connectionRequest);
        System.out.println("value for connectionrequestdetails is " + connectionRequestDetails);
        connectionRequest.setRequestor(connectionRequestDetails.getRequestor());

        final ConnectionRequest updatedConnectionRequest = connectionRequestRepository.save(connectionRequest);

        return ResponseEntity.ok(updatedConnectionRequest);
    }
}

这是运行 junit 测试的输出,具有良好的数据。我已经测试了应用程序,它按预期工作,只有 Junit 失败。

MockHttpServletRequest:
      HTTP Method = PUT
      Request URI = /api/updateDB/1
       Parameters = {}
          Headers = [Content-Type:"application/json;charset=UTF-8"]
             Body = {"requestor":"NEWGUY"}
    Session Attrs = {org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN=org.springframework.security.web.csrf.DefaultCsrfToken@80b6098}

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 = 403
    Error message = Forbidden
          Headers = [X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []



java.lang.AssertionError: Status 
Expected :200
Actual   :403
<Click to see difference>

【问题讨论】:

    标签: java spring-boot unit-testing junit


    【解决方案1】:

    通过使用 csrf,我能够正常工作。

     MockHttpServletRequestBuilder builder =
    
                    put("/api/updateDB/{connectionId}", 1)
                            .contentType("application/json")
                            .content(body3)
                            .contentType(MediaType.APPLICATION_JSON)
                            .with(csrf());
            System.out.println(connectionRequestRepository.findById((long) 1));
            this.mockMvc.perform(builder)
                    .andExpect(content().json(body))
                    .andExpect(status().isOk())
                    .andDo(MockMvcResultHandlers.print());
            System.out.println(connectionRequestRepository.findById((long) 1));
    

    【讨论】:

    • csrf() 方法包含什么?你能解释一下吗?
    【解决方案2】:

    为测试配置文件创建以下内容。

    @EnableWebSecurity
    @Configuration
    @EnableGlobalMethodSecurity(jsr250Enabled = true)
    class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                    .withUser("root").password("system").roles("SYSTEM");
        }
    }
    

    在您的测试类中,

    public class DBcontroltest {
    ...
    
       @Test
       @WithUserDetails(value = "root")
       public void updateTest() throws Exception {
    ...
    }
    

    请访问 github 上的这个项目,我已经使用 spring-security 使用 spring boot 设置了 spring boot 测试。

    测试用例: https://github.com/reflexdemon/shop/blob/master/src/test/java/org/shop/service/CatalogServiceTest.java

    配置: https://github.com/reflexdemon/shop/blob/master/src/main/java/org/shop/WebSecurityConfig.java

    【讨论】:

    • 我不完全遵循。那时我需要使用新的应用程序上下文来运行这些测试。
    • 对于 Spring Boot,您可以添加任意数量的配置文件。那应该没关系。
    • 我的 application.yml 中有以下内容,所以我认为我不需要安全性?安全性:默认任何请求访问:经过身份验证的任何访问路径:-/api/**
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-04
    • 2018-07-06
    • 2020-06-29
    • 1970-01-01
    • 1970-01-01
    • 2020-10-17
    • 1970-01-01
    相关资源
    最近更新 更多