Как мне издеваться над JWT.decode? - PullRequest
0 голосов
/ 28 января 2020

Я использую эту библиотеку в своем загрузочном приложении Spring.

<dependency>
  <groupId>com.auth0</groupId>
  <artifactId>java-jwt</artifactId>
  <version>3.9.0</version>
</dependency>

Как мне выполнить мой модульный тест для DecodedJWT jwt = JWT.decode(accessToken);?

Я мог бы просто передать действительный токен, но это неправильный способ сделать это.

У меня есть этот JwtAuthenticationFilter в моем приложении Spring Boot.

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Value("${clientid}")
    private String clientid;

    @Autowired
    private AuthenticationService authenticationService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException, InvalidRoleException {

        getJwtFromRequest(request, response, filterChain);
    }

    private void getJwtFromRequest(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

            String bearerToken = request.getHeader("Authorization");

            if (!StringUtils.hasText(bearerToken) || !bearerToken.startsWith("Bearer ")) {
                throw new AccessTokenMissingException("No access token found in request headers.");
            }

            try {
                String accessToken = bearerToken.substring(7);

                // this will also throw error when unable to reach auth server
                ResponseEntity<String> result = authenticationService.getUserInfo(accessToken);

                // Invalid access token
                if (!result.getStatusCode().is2xxSuccessful()) {
                    throw new InvalidAccessTokenException("Invalid access token.");
                }

                DecodedJWT jwt = JWT.decode(accessToken);

                String username = jwt.getClaim("preferred_username").asString();
                Map<String, Object> resources = jwt.getClaim("resource_access").asMap();

                Object roles = ((Map<String, Object>) resources.get(clientid)).get("roles");

                List<String> rolesList = (ArrayList<String>)roles;

                UserInfo user = new UserInfo();
                user.setUsername(username);
                user.setRole(rolesList);

                // Step 3: Set username to security context
                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                        user.getUsername(), null, AuthUtil.getAuthRole(user.getRole()));

                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);

            } catch (HttpClientErrorException.Unauthorized | JWTDecodeException e) {
                throw new InvalidAccessTokenException("Invalid access token.");
            }

        filterChain.doFilter(request, response);
    }
}

1 Ответ

0 голосов
/ 28 января 2020

Существуют различные стратегии / опции, которые вы можете использовать, все будут работать:

  1. Не издевайтесь над JWT.decode вообще, рассматривайте его как служебный метод, который должен выполняться внутри тест. Интуиция позади этого, что если бы ваш класс использовал Math.max(a,b) код или, или какие-то манипуляции с датой и временем, такие как DateTime.of(...), вы бы высмеяли это в тесте? Вероятно, нет ... Хотя в этом случае вам, вероятно, придется работать с реально декодируемыми токенами в тесте

  2. Использовать PowerMockito для макетирования вызова stati c (я не очень рекомендую этот способ, но он сделает свою работу, если вы не хотите менять код).

  3. Выполните рефакторинг, извлекая функциональность декодирования для интерфейса и используйте его в качестве зависимости в фильтре:

public interface JWTDecoder {
   DecodedJWT decode(String token); // I assume its string for simplicity
}

@Component
public class StdJWTDecoder implements JWTDecoder {
   public DecodedJWT decode(String token) {
       return JWT.decode(tokent);
}

public class JwtAuthenticationFilter ... {
   private final JWTDecoder jwtDecoder;

   public JwtAuthenticationFilter(JWTDecoder jwtDecoder) {
       this.jwtDecoder = jwtDecoder;
   }

    ....
   private void getJwtFromRequest(HttpServletRequest request, HttpServletResponse 
     response, FilterChain filterChain)  {
      ...
      // instead of:
      DecodedJWT jwt = JWT.decode(accessToken);  
      // use this:
      DecodedJWT jwt = jwtDecoder.decode(accessToken);
      ...
   }

}

При таком подходе Вы можете легко издеваться над JwtDecoder с помощью мокито

...