java - 我如何模拟 JWT.decode?

标签 java spring-boot junit mockito

我在我的 Spring boot 应用程序中使用这个库。

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

如何对 DecodedJWT jwt = JWT.decode(accessToken); 进行单元测试?

我可以传入一个实际的 token ,但这不是正确的方法。

我的 Spring Boot 应用程序中有这个 JwtAuthenticationFilter。

@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. 根本不要模拟 JWT.decode,将其视为应该在测试中运行的实用方法。其背后的直觉是,如果您的类使用 Math.max(a,b) 代码或某些日期时间操作,例如 DateTime.of(...)你会在测试中 mock 它吗?可能不会...尽管在这种情况下,您可能必须在测试中使用真正可解码的 token

  2. 使用 PowerMockito 来模拟静态调用(我真的不推荐这种方式,但如果您不想更改代码,它会完成这项工作)。

  3. 进行重构,将解码功能提取到接口(interface)中,并将其用作过滤器中的依赖项:

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);
      ...
   }

}

通过这种方法,您可以轻松地使用mockito模拟JwtDecoder

关于java - 我如何模拟 JWT.decode?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59942695/

相关文章:

java - 无法使用在 Java 中链接接口(interface)的方法模拟类

java - 检查目录是否可以打开并列出其文件

java - 我应该为 List< 类型的参数设置什么值?扩展 Map<String, ?>>?

java - Intellij Spring Boot 运行配置

spring-boot - 带有Kotlin安装问题的Spring Boot Gradle项目

java - Junit 在 Eclipse 中通过,在 Jenkins 中失败

android - 使用 LiveData 的 JUnit5 测试不执行订阅者的回调

java - 在 XSLT 中对记录进行分组时如何避免 O(n^2) 的复杂性?

JAVA - for 循环中的 length()

java - Spring Boot 和数据库默认数据与 Mongodb