简体   繁体   中英

MockMvc throws internal exception instead of returning response with 4xx status code

I am trying to write a JwtTokenVerifier test using MockMvc

When I trying to request some API with an invalid Auth header: instead of returning a response with 4xx status code, it throws an internal exception (AuthException in my case). Should I expect this exception in the test or I need to do something to get a response?

(test succeeds for values "" and "123", but fails for "Bearer qewqweqweqwe" with an AuthException (io.jsonwebtoken.MalformedJwtException: JWT strings must contain exactly 2 period characters. Found: 0))

Test:

@ParameterizedTest
    @ValueSource(strings = {"", "123", "Bearer qewqweqweqwe"})
    public void throwsClientErrorOnRequestWithInvalidAuthHeader(String headerValue) throws Exception {
        String requestBody = asJsonString(new CustomPageRequest());

        mockMvc.perform(
                MockMvcRequestBuilders.post("/users/paged")
                        .header(jwtConfig.getAuthorizationHeader(), headerValue)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(requestBody))
                .andExpect(status().is4xxClientError());
    }

JwtTokenVerifier filter:

public class JwtTokenVerifier extends OncePerRequestFilter {

    //DI

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        String authHeader = request.getHeader(jwtConfig.getAuthorizationHeader());
        if (StringUtils.isEmpty(authHeader) || !authHeader.startsWith(jwtConfig.getTokenPrefix())) {
            logger.warn("Invalid Authorization header - '" + authHeader + "'");
            filterChain.doFilter(request, response);
            return;
        }
        try {
            Claims body = getTokenBodyFromAuthHeader(authHeader);

            String username = body.getSubject();

            AuthUser userDetails = userDetailsService.loadUserByUsername(username);
            CustomTokenBasedAuthentication authentication = new CustomTokenBasedAuthentication(userDetails);
            SecurityContextHolder.getContext().setAuthentication(authentication);
            userContext.setCurrentPrincipal(authentication);
        } catch (JwtException e) {
            logger.error("During authentication (token verification) exception occurred", e);
            throw new AuthException("auth error");
        }
        filterChain.doFilter(request, response);
    }

    ...
}

ApiExceptionHandler:

@ControllerAdvice(basePackages = {"bac9h.demoapp"})
public class ApiExceptionsHandler {

    ...

    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ExceptionHandler(AuthException.class)
    @ResponseBody
    public String onAuthException(AuthException e) {
        return "401 error: " + e.getMessage();
    }
}

It looks as though everything is wired up and working properly, however your JWT parser recognises that the Bearer token you are providing isn't even a valid format for a JWT, so it's throwing exception.

I'd suggest creating a JWT in the correct format that does not make sense in your application context to test the behaviour you're trying to verify.在您的应用程序上下文中没有意义来测试您尝试验证的行为。 Try jwt.io .

I realized that my apiExceptionHandler does not work for the filter

Make simple servlet filter work with @ControllerAdvice :

As specified by the java servlet specification Filters execute always before a Servlet is invoked. Now a @ControllerAdvice is only useful for controller which are executed inside the DispatcherServlet. So using a Filter and expecting a @ControllerAdvice or in this case the @ExceptionHandler, to be invoked isn't going to happen.

and in order to get appropriate response i need to manually provide exception handler

Testing Spring MVC @ExceptionHandler method with Spring MVC Test

@Before
public void setup() {
    this.mockMvc = MockMvcBuilders.standaloneSetup(statusController)
         .setControllerAdvice(new ExceptionController())
        .build();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM