我有一个 Spring OncePerRequestFilter 过滤器,它具有 doFilterInternal 的实现,如下所示:
@Override
protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws ServletException, IOException {
final Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null && containsRole(auth, "SpecificRole")) {
doThingsWithTheRequest(request);
}
filterChain.doFilter(request, response);
}
并且 containsRole 看起来像这样:
protected boolean containsRole(final Authentication auth, final String role) {
for (final GrantedAuthority ga : auth.getAuthorities()) {
if (ga.getAuthority().equals(role)) {
return true;
}
}
return false;
}
对于我的测试,我有这个 JUnit 测试,我想在其中模拟 Authentication.getAuthorities() 以便 containsRole 将返回 true:
@Test
public void test() throws ServletException, IOException, CommerceCartRestorationException {
SecurityContext securityContextMock = mock(SecurityContext.class);
Authentication authenticationMock = mock(Authentication.class);
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("MyRole");
Collection<SimpleGrantedAuthority> authCollection = Collections.singleton(simpleGrantedAuthority);
when(authenticationMock.getAuthorities()).thenReturn(authCollection);
when(securityContextMock.getAuthentication()).thenReturn(authenticationMock);
SecurityContextHolder.setContext(securityContextMock);
testObj.doFilterInternal(httpServletRequestMock, httpServletResponseMock, filterChainMock);
}
我收到编译器错误
无法解析方法“thenReturn(Collection)”
在这一行:
when(authenticationMock.getAuthorities()).thenReturn(authCollection);
getAuthorities 返回此
Collection<? extends GrantedAuthority>
并且 SimpleGrantedAuthority 实现了 GrantedAuthority 接口
所以问题是为什么以及如何解决它?
我见过类似的问题,其答案是添加对 spring-security-test 的依赖并使用 @WithMockUser 但恐怕使用 spring-security-test 不是一个选项
Authentication#getAuthorities
的返回类型为 Collection<? extends GrantedAuthority>
,它是通配符类型。您不知道实际类型是什么,因此无法为其赋值或将其用作另一个方法中的参数。
一个简单的解决方法是转换为原始集合类型:
Mockito.when(authenticationMock.getAuthorities())
.thenReturn((Collection) authorityCollection);
但更可持续的解决方案是首先不要模拟
Authentication
接口,而是使用专门实现来支持测试的实现:TestingAuthenticationToken
:
final Authentication authentication = new TestingAuthenticationToken(
null, // principal
null, // credentials
"MyRole"); // authority roles