@AuthenticationPrincipal对象返回存储在会话中的上一个值。
Spring引导+Spring安全oauth REST服务器。https://github.com/legshort/spring-boot-sample
这两种REST方法都在控制器中。问题是,当我运行测试代码时,deleteUser()处的最后一个参数userDetailsImpl和updateUser()的userDetailsImpl的值相同。
@RequestMapping(method = RequestMethod.PUT, value = "/users/{userId}")
public ResponseEntity updateUser(@PathVariable Long userId,
@AuthenticationPrincipal UserDetailsImpl userDetailsImpl,
@Valid @RequestBody UserUpdateForm userUpdateForm,
BindingResult bindingResult) {
logger.info("UserUpdate: " + userUpdateForm);
User updatedUser = userService.updateUser(userUpdateForm
.createUser(userId));
return new ResponseEntity(updatedUser, HttpStatus.OK);
}
@RequestMapping(method = RequestMethod.DELETE, value = "/users/{userId}")
public ResponseEntity deleteUser(@PathVariable Long userId,
@AuthenticationPrincipal UserDetailsImpl userDetailsImpl) {
logger.info("UserDelete: " + userId);
User requestedUser = new User(userId);
userService.deleteUser(requestedUser);
return new ResponseEntity(HttpStatus.NO_CONTENT);
}
以下是控制器测试代码
我不知道是怎么回事,但第二个请求是testDeleteUser(),它有会话值,并且是使用上一个测试的同一个用户。因此,即使在deleteUser()开始时认为验证访问令牌并加载正确的新用户,但userDetailsImpl的实际值在testUpdateUser()的开始时创建了错误的用户。
@Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).addFilters(filterChainProxy).build();
}
@Test
public void testUpdateUser() throws Exception {
User savedUser = signUpUser();
// @formatter:off
mockMvc.perform(
put("/users/" + savedUser.getId())
.header(HeaderUtil.AUTHORIZATION, getAuthorizationWithAccessToken())
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(UserUpdateFormFactory.newInstance())))
.andExpect(status().isOk())
.andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.id", is(greaterThan(NumberUtils.INTEGER_ZERO))))
.andExpect(jsonPath("$.name", is(equalTo(StringUtil.NEW + UserFactory.NAME))));
// @formatter:on
}
@Test
public void testDeleteUser() throws Exception {
User savedUser = signUpUser();
String authorization = getAuthorizationWithAccessToken();
// @formatter:off
mockMvc.perform(
delete("/users/" + savedUser.getId())
.header(HeaderUtil.AUTHORIZATION, authorization)
.contentType(TestUtil.APPLICATION_JSON_UTF8))
.andDo(print())
.andExpect(status().isNoContent());
// @formatter:on
}
这是UserDetailService实现,当它使用loadUserByUserName()来验证访问令牌时,它会从数据库中加载正确的用户,并返回刚刚在每个测试方法(signUpUser())开始时创建的新用户。
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserService userService;
@Override
public UserDetails loadUserByUsername(String email)
throws UsernameNotFoundException {
User requestedUser = new User();
requestedUser.setEmail(email);
User savedUser = userService.findByEmail(requestedUser);
return new UserDetailsImpl(savedUser);
}
}
我试图禁用会话,但我失败了,对我来说,配置和测试代码似乎很好。对于spring安全oauth,有什么好的实际例子吗?
更新
就我对mockMvc的了解而言,它清除了所有设置,并且每次都使用setUp()方法创建了相当多的新mock服务器。因此,每次都应该清除访问令牌存储,但令牌存储会以某种方式维护经过身份验证的令牌。
询问在测试期间提交的使用"/oauth/token"请求的访问令牌,下面是调用InMemoryTokenStore的方式。
测试过程日志
testUpdateUser()->POST:/oauth/token->存储令牌
代币:50b10897-9e15-4859-aeb0-43d0802ba42c
user:id=2testUpdateUser()->PUT:/users/2->read令牌
代币:50b10897-9e15-4859-aeb0-43d0802ba42c
user:id=2testUpdateUserWithWrongUserId()->GET:/oauth/token->存储令牌
令牌:50b10897-9e15-4859-aeb0-43d0802ba42c->已存在于令牌中
user:id=2->id=4:用户更新了一个新的testUpdateUserWithWrongUserId()->PUT:/users/0->读取令牌
代币:50b10897-9e15-4859-aeb0-43d0802ba42c
user:id=2testDeleteUser()->GET:/oauth/token->未存储令牌,应存储令牌
testDeleteUser()->DELETE:/users/5->读取令牌
代币:50b10897-9e15-4859-aeb0-43d0802ba42c
user:id=2->user应该是使用userSignUp()创建的id=5
问题
如何使用mockMvc清除InMemoryTokenStore的每个测试方法?
// ignore spring security session
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);