具有自定义身份验证主体的MockMVC测试

时间:2019-12-05 18:28:44

标签: java spring-boot unit-testing mockmvc

我正在尝试为API端点编写测试,但无法超越安全性。至少那是我所了解的情况。 根据我对文档(https://docs.spring.io/spring-security/site/docs/5.0.x/reference/html/test-method.html的了解,我认为我在遵循正确的方法?

我的Rest控制器如下所示。我有一个导致问题的身份验证主体。

@RestController
@RequestMapping("/api")
public class VehicleResource {
@GetMapping(value = "/status", produces = { MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<StatusResponse> getStatus(@AuthenticationPrincipal CustomUser customUser) {
    StatusResponse statusResponse = vehicleService.getStatus(customUser.getVin());
    LOGGER.debug("Sent statusResponse: {}", statusResponse);

    return new ResponseEntity<>(statusResponse, HttpStatus.OK);
}

我的测试非常简单:

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringBootTest(classes = { MobileBackendApplication.class })
    @AutoConfigureMockMvc
    public class VehicleResourceTest {
        @Autowired
        private MockMvc mockMvc;
    private AccountCredentials testCredentials;
    @Before
        public void setUp() throws Exception {
            MockitoAnnotations.initMocks(this);
        testCredentials = new AccountCredentials("test.user@test.com", "testPassword");
}
@Test
    @WithMockCustomUser
    public void getStatusTest() throws Exception {

        mockMvc.perform(
                get("/api/status").with(httpBasic(testCredentials.getUsername(), testCredentials.getPassword())))
                .andExpect(status().isOk());
    }

我有一个MockCustomUser界面,因此可以传递自定义用户:

@WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory.class)
public @interface WithMockCustomUser {
    String username() default "test.user@bmw.com";

    String password() default "testPassword";

    String vin() default "123TEST456VIN789";

    String pushNotificationId() default "testPushId";
}

使用WithMockCustomUserSecurityContextFactory:

public class WithMockCustomUserSecurityContextFactory implements WithSecurityContextFactory<WithMockCustomUser> {

    @Override
    public SecurityContext createSecurityContext(WithMockCustomUser customUser) {
        SecurityContext context = SecurityContextHolder.createEmptyContext();

        CustomUser principal = new CustomUser(customUser.username(), customUser.password(), customUser.vin(),
                new ArrayList<String>(Arrays.asList(customUser.pushNotificationId())), null,
                AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER"));
        Authentication auth = new UsernamePasswordAuthenticationToken(principal, "password",
                principal.getAuthorities());
        context.setAuthentication(auth);
        return context;
    }
}

运行测试时,我收到的是401未经授权,而不是200。其他答案可能缺少基本身份验证标头,但我似乎将它传递了出去。下面是我运行测试时打印的内容。

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /api/status
       Parameters = {}
          Headers = {Authorization=[Basic dGVzdC51c2VyQHNhbXBsZS5jb206dGVzdFBhc3N3b3Jk]}
             Body = null
    Session Attrs = {}

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 = Unauthorized
          Headers = {Access-Control-Allow-Origin=[*], Access-Control-Allow-Methods=[POST, GET], Access-Control-Max-Age=[3600], Access-Control-Allow-Headers=[Origin, X-Requested-With, Content-Type, Accept, Authorization], Access-Control-Expose-Headers=[Authorization], WWW-Authenticate=[Basic realm="Realm"], 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 = []

0 个答案:

没有答案