我尝试使用spring的MockMvc类在我的spring启动应用程序中测试我的spring OAuth2授权和身份验证。我面临的根本问题是,即使我已将其注册为spring security使用的身份验证提供程序之一,我的自定义身份验证提供程序也从未被调用过。我按照发现here和here的春季安全教程进行了操作。
代码段 安全配置程序类 - 这是添加自定义身份验证提供程序的位置。
@Configuration
@EnableWebSecurity
public class SecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
private AuthenticationProvider authenticationProvider;
@Override
public void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(authenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic();
}
}
自定义身份验证提供程序 - 这应该进行实际身份验证
@Component
public class UsernamePasswordAuthProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials()
.toString();
if ("test".equals(username) && "test".equals(password)) {
Collection<? extends GrantedAuthority> grantedAuthorityList = authentication
.getAuthorities();
return new UsernamePasswordAuthenticationToken
(username, password, grantedAuthorityList);
} else {
throw new
BadCredentialsException("External system authentication failed");
}
}
@Override
public boolean supports(Class<?> auth) {
return true;
}
}
Spring启动集成测试 - 这是MockMvc使用Web应用程序上下文实例化的地方
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ConfigurationServiceApplication.class)
public class SettingsAPITest {
private MockMvc mockMvc;
@Autowired
private WebApplicationContext wac;
@Autowired
private FilterChainProxy springSecurityFilterChain;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
.addFilter(springSecurityFilterChain).build();
}
@Test
public void testGetStatus() throws Exception {
//execute test
mockMvc.perform(get("/status")
.with(httpBasic("test","test")))
.andDo(print())
.andExpect(status().isOk());
}
}
这是控制器
@RestController
public class StatusController{
@RequestMapping(method = RequestMethod.GET)
public ResponseEntity<String> getStatus(){
return new ResponseEntity<>("I'm Ok", HttpStatus.OK);
}
}
运行测试会返回401并设置断点并通过它进行调试,这表明从不使用自定义身份验证提供程序。
MockHttpServletRequest:
HTTP Method = GET
Request URI = /status
Parameters = {}
Headers = {Authorization=[Basic dGVzdDp0ZXN0]}
Handler:
Type = null
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 401
Error message = null
Headers = {X-Content-Type-Options=[nosniff], X-XSS-Protection=[1; mode=block], Cache-Control=[no-cache, no-store, max-age=0, must-revalidate, no-store], Pragma=[no-cache, no-cache], Expires=[0], X-Frame-Options=[DENY], WWW-Authenticate=[Bearer realm="oauth2-resource", error="unauthorized", error_description="Full authentication is required to access this resource"], Content-Type=[application/json;charset=UTF-8]}
Content type = application/json;charset=UTF-8
Body = {"error":"unauthorized","error_description":"Full authentication is required to access this resource"}
Forwarded URL = null Redirected URL = null
Cookies = []
java.lang.AssertionError: Status Expected :200 Actual :401
我感觉我的webapp上下文配置正被某个地方的spring boot覆盖(因为这里的大部分内容都是由spring boot自动配置的),但我无法证明这一点。任何帮助真的很感激!!感谢
仅供参考,我查看了相关帖子
答案 0 :(得分:0)
您可以尝试从
更改mockmvc初始化@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
.addFilter(springSecurityFilterChain).build();
}
到
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
.apply(springSecurity()).build();
}
答案 1 :(得分:0)
我使用了this教程来设置身份验证提供程序。为了测试,这是我的设置:
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.client.RestTemplate;
@RunWith(SpringRunner.class)
@WebMvcTest(MyController.class)
public class MyControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private RestTemplate restTemplate;
@TestConfiguration
static class AdditionalConfig {
@Bean
public MyAuthenticationProvider productValidator() {
return new MyAuthenticationProvider();
}
}
@Test
public void shouldGetDocuments() throws Exception {
this.mockMvc.perform(post("/partners/links/")
.with(httpBasic("user", "password")))
.andExpect(status().isOk())
.andReturn();
}
}
请记住,如果您忘记在测试中提供凭据(在我的情况下为基本身份验证),则不会调用您的自定义身份验证提供程序。 >
答案 2 :(得分:0)
要模拟 AuthenticationProvider
,请在 #RequestBuilder
中使用您的授权模型。例如,SecurityMockMvcRequestPostProcessors.httpBasic()
。
此外,如果您的授权需要标题,您可以添加它们。
@Test
fun `when authenticated user requests a secure endpoint, then success`() {
val requestBuilder = MockMvcRequestBuilders
.get(provideFullUrl(SecurityCoreEndpointsTest.Keys.SECURE))
.with(httpBasic("your-username", "your-password"))
.header("Header-Key", "Value")
val resultMatcher = MockMvcResultMatchers.status().isOk
mockMvc.perform(requestBuilder).andExpect(resultMatcher)
}
注意:使用 @WithMockUser
对我不起作用
GL