@AuthenticationPrincipal对象返回会话值



@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,有什么好的实际例子吗?


更新

  1. 就我对mockMvc的了解而言,它清除了所有设置,并且每次都使用setUp()方法创建了相当多的新mock服务器。因此,每次都应该清除访问令牌存储,但令牌存储会以某种方式维护经过身份验证的令牌。

  2. 询问在测试期间提交的使用"/oauth/token"请求的访问令牌,下面是调用InMemoryTokenStore的方式。


测试过程日志

  1. testUpdateUser()->POST:/oauth/token->存储令牌
    代币:50b10897-9e15-4859-aeb0-43d0802ba42c
    user:id=2

  2. testUpdateUser()->PUT:/users/2->read令牌
    代币:50b10897-9e15-4859-aeb0-43d0802ba42c
    user:id=2

  3. testUpdateUserWithWrongUserId()->GET:/oauth/token->存储令牌
    令牌:50b10897-9e15-4859-aeb0-43d0802ba42c->已存在于令牌中
    user:id=2->id=4:用户更新了一个新的

  4. testUpdateUserWithWrongUserId()->PUT:/users/0->读取令牌
    代币:50b10897-9e15-4859-aeb0-43d0802ba42c
    user:id=2

  5. testDeleteUser()->GET:/oauth/token->未存储令牌,应存储令牌

  6. 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);

最新更新