我正在为我的Rest应用程序编写集成测试。我写了一个测试来检查accesDenied,它引发了一个UsernameNotFoundException,它应该,但它不会跟随返回JSON的@ControllerAdvice类的异常。
代码在执行时正常工作,返回Json,在其他测试用例中,例如AuthenticationFailed - whcih也由异常处理 - ,Json返回运行测试。在这种情况下json不返回,可能是因为我有一个自定义UserDetailsService?
我已经在互联网上看过,其他人只是测试是否有异常,并致电当天。然而,我喜欢测试返回与执行相同的行为--Json。可能吗?我错过了什么?
我尝试过类似的问题'答案,但他们没有工作,返回相同的行为。
非常感谢任何帮助。 Thx提前, 阿方索
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { TestConfig.class })
@WebAppConfiguration
public class SecurityIntegrationTest {
private final String SECURED_URI = "/users/1";
private final String LOGIN_URI = "/login";
@Autowired
private WebApplicationContext wac;
@Autowired
private FilterChainProxy springSecurityFilter;
@Autowired
CustomUserDetailsService customUserDetailsService;
@Autowired
UserController userController;
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac)
.addFilters(springSecurityFilter).alwaysDo(print()).build();
}
@Test
public void requiresAuthentication() throws Exception {
mockMvc.perform(
get(SECURED_URI).contentType(
MediaType.valueOf(Constants.REST_TYPE)))
.andExpect(status().isUnauthorized())
.andExpect(
content().contentType(
MediaType.valueOf(Constants.REST_TYPE)))
.andExpect(content().string(Jsons.AUTHENTICATION_REQUIRED));
}
@Test
public void authenticationFailed() throws Exception {
mockMvc.perform(formLogin())
.andExpect(status().isUnauthorized())
.andExpect(
content().contentType(
MediaType.valueOf(Constants.REST_TYPE)))
.andExpect(content().string(Jsons.AUTHENTICATION_FAILED));
}
@Test
public void authenticationSuccess() throws Exception {
mockMvc.perform(formLogin().user("Ikos").password("Ikos"))
.andExpect(status().isOk())
.andExpect(
content().contentType(
MediaType.valueOf(Constants.REST_TYPE)))
.andExpect(
content().string(
String.format(Jsons.LOGIN, "Ikos", "Ikos")));
}
@Test
public void accessGranted() throws Exception {
UserDetails user = customUserDetailsService.loadUserByUsername("Ikos");
mockMvc.perform(
get(SECURED_URI).with(user(user)).contentType(
MediaType.valueOf(Constants.REST_TYPE)))
.andExpect(status().isOk())
.andExpect(
content().contentType(
MediaType.valueOf(Constants.REST_TYPE)))
.andExpect(content().string(RestDataFixture.defaultUserJSON()));
}
@Test
public void accessDenied() throws Exception {
UserDetails user = customUserDetailsService.loadUserByUsername("Pedro");
mockMvc.perform(
get(SECURED_URI).with(user(user)).contentType(
MediaType.valueOf(Constants.REST_TYPE)))
.andExpect(status().isUnauthorized())
.andExpect(
content().contentType(
MediaType.valueOf(Constants.REST_TYPE)))
.andExpect(content().string(Jsons.AUTHENTICATION_REQUIRED));
}
}
@Configuration
@ComponentScan(basePackages = { "es.aekia.rest" })
@EnableWebMvc
public class TestConfig {
}
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserDao userDao;
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
User user;
try {
user = userDao.findByAlias(username);
if (user == null)
throw new UsernameNotFoundException("user name not found");
} catch (DataAccessException e) {
throw new UsernameNotFoundException("database error");
}
return buildUserFromUserEntity(user);
}
private UserDetails buildUserFromUserEntity(User userEntity) {
// convert model user to spring security user
String username = userEntity.getAlias();
String password = userEntity.getPassword();
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_"
+ userEntity.getRole());
authorities.add(authority);
UserDetails springUser = new org.springframework.security.core.userdetails.User(
username, password, authorities);
return springUser;
}
}
@ControllerAdvice
public class ExceptionController {
@RequestMapping(produces = { Constants.REST_TYPE })
@ExceptionHandler({ MissingServletRequestParameterException.class,
UnsatisfiedServletRequestParameterException.class,
HttpRequestMethodNotSupportedException.class,
ServletRequestBindingException.class,
MethodArgumentNotValidException.class })
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public @ResponseBody Map<String, Object> handleRequestException(Exception ex) {
Map<String, Object> map = Maps.newHashMap();
map.put(Constants.ERROR, Constants.REQUEST_ERROR);
map.put(Constants.CAUSE, ex.getMessage());
return map;
}
@RequestMapping(produces = { Constants.REST_TYPE })
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
@ResponseStatus(value = HttpStatus.UNSUPPORTED_MEDIA_TYPE)
public @ResponseBody Map<String, Object> handleUnsupportedMediaTypeException(
HttpMediaTypeNotSupportedException ex) throws IOException {
Map<String, Object> map = Maps.newHashMap();
map.put(Constants.ERROR, Constants.UNSUPPORTED_MEDIA_TYPE);
map.put(Constants.CAUSE, ex.getLocalizedMessage());
map.put(Constants.SUPPORTED, ex.getSupportedMediaTypes());
return map;
}
@RequestMapping(produces = { Constants.REST_TYPE })
@ExceptionHandler({ AccessDeniedException.class,
UsernameNotFoundException.class })
@ResponseStatus(value = HttpStatus.UNAUTHORIZED)
public @ResponseBody Map<String, Object> handleAccesDeniedException(
Exception ex) {
Map<String, Object> map = Maps.newHashMap();
map.put(Constants.ERROR, Constants.ACCESS_DENIED);
map.put(Constants.CAUSE, ex.getMessage());
return map;
}
@RequestMapping(produces = { Constants.REST_TYPE })
@ExceptionHandler(Exception.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public @ResponseBody Map<String, Object> handleUncaughtException(
Exception ex) throws IOException {
Map<String, Object> map = Maps.newHashMap();
map.put(Constants.ERROR, Constants.UNKNOWN_ERROR);
if (ex.getCause() != null) {
map.put(Constants.CAUSE, ex.getCause().getMessage());
} else {
map.put(Constants.CAUSE, ex.getMessage());
}
return map;
}
}
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
@Autowired
private RestAccessDeniedHandler restAccessDeniedHandler;
@Autowired
private RestAuthSuccessHandler restAuthSuccessHandler;
@Autowired
private RestAuthFailureHandler restAuthFailureHandler;
@Autowired
private RestLogoutSuccessHandler restLogoutSuccessHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.disable()
/*
* .authenticationProvider(authenticationProvider())
*/
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.accessDeniedHandler(restAccessDeniedHandler)
.and()
.formLogin()
.permitAll()
.loginProcessingUrl("/login")
// .usernameParameter(USERNAME)
// .passwordParameter(PASSWORD)
.successHandler(restAuthSuccessHandler)
.failureHandler(restAuthFailureHandler).and()
.logout()
.permitAll()
// .logoutRequestMatcher(new AntPathRequestMatcher(LOGIN_PATH,
// "DELETE"))
.logoutSuccessHandler(restLogoutSuccessHandler).and()
.sessionManagement().maximumSessions(1);
// .logoutSuccessUrl("/logout").and()
/*
* .sessionManagement() .sessionCreationPolicy (SessionCreationPolicy
* .STATELESS).and()
*/
//
http.authorizeRequests().antMatchers(HttpMethod.POST, "/login")
.permitAll().antMatchers(HttpMethod.POST, "/logout")
.authenticated().antMatchers(HttpMethod.GET, "/users")
.permitAll().antMatchers(HttpMethod.GET, "/users/**")
.hasAnyRole("USER", "ADMIN")
.antMatchers(HttpMethod.POST, "/**").hasRole("ADMIN")
.antMatchers(HttpMethod.PUT, "/**").hasRole("ADMIN")
.antMatchers(HttpMethod.PATCH, "/**").hasRole("ADMIN")
.antMatchers(HttpMethod.DELETE, "/**").hasRole("ADMIN");
// .anyRequest().anonymous();
}
}