【问题标题】:Testing access token filter测试访问令牌过滤器
【发布时间】:2020-07-13 12:08:47
【问题描述】:

我创建了一个 Bearer 令牌创建器,当我编写它的测试时,测试总是失败并返回 nullPointerException 有什么问题?

注意:不记名令牌语法类似于 [Bearer {someEncodedCharacter}]。

import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;

@SpringBootTest
public class JwtTokenFilterTest {

  @MockBean
  private HttpServletRequest httpRequest;
  @MockBean
  private TokenManager tokenManagerTester;
  @MockBean
  private Authentication authentication;
  @MockBean
  private SecurityContext securityContext;
  @MockBean
  private HttpServletResponse httpResponse;
  @MockBean
  private FilterChain filterChain;
  @Test
  public void givenHttpServletRequestandHttpServletResponseandFilterChainDoFilterInternal()
      throws ServletException, IOException {
    String token="eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhYmMxMjMiLCJpc3MiOiJ3d3cuYWJjLmNvbSIsImlhdCI6MTU5NDY0MTUzNywiZXhwIjoxNTk0NjQxODM3fQ.GHzVaQW_tvqo8HlDmoXzZ8WIYGcLHciLOSMFxsZUOsY";
    Mockito.when(httpRequest.getHeader("Authorization")).thenReturn("Bearer "+token);
    Mockito.when(securityContext.getAuthentication()).thenReturn(authentication);
    SecurityContextHolder.setContext(securityContext);
    Mockito.when(tokenManagerTester.tokenValidate(Mockito.anyString())).thenReturn(true);
    Mockito.when(tokenManagerTester
        .getUsernameToken(token))
        .thenReturn("abc123");


    JwtTokenFilter filter=new JwtTokenFilter();

    filter.doFilterInternal(httpRequest, httpResponse, filterChain);
    Mockito.verify(filterChain,Mockito.times(1));

  }


}

这里是 JwtfFilter:

@Component
public class JwtTokenFilter extends OncePerRequestFilter {



    @Autowired
    private TokenManager tokenManager;

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest,
                                    @NotNull HttpServletResponse httpServletResponse,
                                    @NotNull FilterChain filterChain) throws ServletException, IOException {

        /**
         * We are parsing our token in two pieces and we process the second
         * "Bearer hvs231asas2355"
         */
        final String authHeader = httpServletRequest.getHeader("Authorization");
        /* */
        String username = null;
        String token = null;


        if (authHeader != null && authHeader.contains("Bearer")) {
            token = authHeader.substring(7);
            try {
                username = tokenManager.getUsernameToken(token);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }

        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            if (tokenManager.tokenValidate(token)) {
                UsernamePasswordAuthenticationToken upassToken =
                        new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
                upassToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
                SecurityContextHolder.getContext().setAuthentication(upassToken);
            }
        }

        filterChain.doFilter(httpServletRequest, httpServletResponse); 
    }
}

注 2:我认为如果我控制 filterChain.dofilter 我可以看到该方法工作正常。出于这个原因,我写了 Mockito.verify(filterChain,Mockito.times(1));

【问题讨论】:

    标签: java spring spring-boot testing spring-security


    【解决方案1】:

    您的测试类顶部缺少 @SpringBootTest@WebMvcTest 注释。这就是 Spring 不模拟依赖 bean 的原因。

    或者你可以使用 Mockito:

    @RunWith(MockitoJUnitRunner.class)
    public class JwtTokenFilterTest {
    
      @Mock
      private HttpServletRequest httpRequest;
      @Mock
      private TokenManager tokenManagerTester;
      @Mock
      private Authentication authentication;
      @Mock
      private SecurityContext securityContext;
      @Mock
      private HttpServletResponse httpResponse;
      @Mock
      private FilterChain filterChain;
      
      @InjectMocks
      private JwtTokenFilter filter=new JwtTokenFilter();
      
      @Test
      public void givenHttpServletRequestandHttpServletResponseandFilterChainDoFilterInternal()
          throws ServletException, IOException {
        String token="eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhYmMxMjMiLCJpc3MiOiJ3d3cuYWJjLmNvbSIsImlhdCI6MTU5NDY0MTUzNywiZXhwIjoxNTk0NjQxODM3fQ.GHzVaQW_tvqo8HlDmoXzZ8WIYGcLHciLOSMFxsZUOsY";
        Mockito.when(httpRequest.getHeader("Authorization")).thenReturn("Bearer "+token);
        Mockito.when(securityContext.getAuthentication()).thenReturn(authentication);
        SecurityContextHolder.setContext(securityContext);
        Mockito.when(tokenManagerTester.tokenValidate(Mockito.anyString())).thenReturn(true);
        Mockito.when(tokenManagerTester
            .getUsernameToken(token))
            .thenReturn("abc123");
        filter.doFilterInternal(httpRequest, httpResponse, filterChain);
        Mockito.verify(filterChain,Mockito.times(1));
    
      }
    
    
    }
    

    【讨论】:

    • 感谢您的回答,但结果仍然相同。添加这些并不能解决问题。
    • @LeoS 您究竟在哪一行得到空指针异常?你可以分享有问题的堆栈跟踪吗?
    • 我在上面分享了它,但由于stackoverflow的分页它保持在右侧,我现在修复它。
    • @LeoS 能否请您编写整个测试类,包括您在顶部包含的注释和导入。
    • 修复了它还添加了导入。
    【解决方案2】:

    问题是我使用了 MockBean 而不是 Mock。

      private static HttpServletRequest httpRequest;
    
      private static TokenManager tokenManagerTester;
    
      private static Authentication authentication;
    
      private static SecurityContext securityContext;
    
      private static HttpServletResponse httpResponse;
    
      private static FilterChain filterChain;
      @BeforeClass
      public static void setUp(){
        httpResponse = mock(HttpServletResponse.class);
        filterChain=mock(FilterChain.class);
        securityContext=mock(SecurityContext.class);
        authentication=mock(Authentication.class);
        tokenManagerTester=mock(TokenManager.class);
        httpRequest=mock(HttpServletRequest.class);
      }
    

    【讨论】:

    • 请避免将模拟变量定义为静态变量。不是最佳实践。请检查我的答案。
    猜你喜欢
    • 2013-03-24
    • 2018-07-23
    • 2013-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多