Spring @AuthenticationPrincipal对象返回会话值

Spring @AuthenticationPrincipal对象返回会话值,spring,rest,spring-security,spring-test,spring-security-oauth2,Spring,Rest,Spring Security,Spring Test,Spring Security Oauth2,@AuthenticationPrincipal对象返回会话中存储的上一个值 Spring引导+Spring安全oauth REST服务器 这两种休息方法都在控制器中。问题是,当我运行测试代码时,deleteUser()处的最后一个参数userDetailSiml和updateUser()处的userDetailSiml的值相同 @RequestMapping(method = RequestMethod.PUT, value = "/users/{userId}") public Respon

@AuthenticationPrincipal对象返回会话中存储的上一个值

Spring引导+Spring安全oauth REST服务器

这两种休息方法都在控制器中。问题是,当我运行测试代码时,deleteUser()处的最后一个参数userDetailSiml和updateUser()处的userDetailSiml的值相同

@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()开始时创建了错误的用户

这是UserDetailService实现,当需要loadUserByUserName()来验证访问令牌时,它会从数据库中加载适当的用户,并返回在每个测试方法(signUpUser())开始时刚刚创建的新用户

我试图禁用我失败的会话,配置和测试代码对我来说似乎没问题。 SpringSecurityOAuth有什么好的实用例子吗


已更新

  • 据我对mockMvc的了解,它清除所有设置,每次都使用setUp()方法创建新的模拟服务器。因此,每次都应该清除访问令牌存储,但令牌存储以某种方式维护经过身份验证的令牌

  • 在测试过程中使用“/oauth/token”请求访问令牌,下面是调用InMemoryTokenStore的方式


  • 测试过程日志

  • testUpdateUser()->POST:/oauth/token->store token
    代币:50b10897-9e15-4859-aeb0-43d0802ba42c
    用户:id=2

  • testUpdateUser()->PUT:/users/2->读取令牌
    代币:50b10897-9e15-4859-aeb0-43d0802ba42c
    用户:id=2

  • TestUpdateUserWithErrorUserId()->GET:/oauth/token->store token
    令牌:50b10897-9e15-4859-aeb0-43d0802ba42c->已存在于令牌中
    用户:id=2->id=4:用户已更新为新用户

  • TestUpdateUserWithErrorUserId()->PUT:/users/0->读取令牌
    代币:50b10897-9e15-4859-aeb0-43d0802ba42c
    用户:id=2

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

  • testDeleteUser()->删除:/users/5->读取令牌
    代币:50b10897-9e15-4859-aeb0-43d0802ba42c
    user:id=2->user应该是id=5,这是用userSignUp()创建的


  • 问题

    如何使用mockMvc清除InMemoryTokenStore中的每个测试方法?

    您只使用wac(WebApplicationContext)的一个实例,因此主体存储在两个测试执行之间。为什么不在每个测试中显式地设置主体,比如
    delete(“/users/”+savedUser.getId()).principal(null)
    ?AuthenticationPrincipal应该是SecurityContextHolder.getContext().getAuthentication().getPrincipal(),所以这是预期的行为。我想我正在努力弄清楚您希望代码做什么。@谢谢您的评论。我想用干净的状态测试每个方法,这样我希望没有会话或主体。每个测试方法,我理解的是每个测试方法都应该干净,以防止任何其他奇怪的行为。@gsolecki感谢您的指导,但是,主体()不接受null,并且很难找到我应该如何调用主体(),你能给我一个更具体的例子吗?@RobWinch我认为SpringSecurityOAuth应该只依赖于每个测试的请求头中的accessToken。如果我在测试代码上出错,请让我指导正确的测试。也许解释一下你必须把代码放在哪里,解释一下为什么它应该解决这个问题,这样你的回答质量会更好。你需要扩展WebSecurity配置适配器并放置http.sessionManagement().sessionCreationPolicy(sessionCreationPolicy.NEVER)在那里。这是因为rest服务是无状态的,会话持有状态,但因为会话中持有的状态与数据无关,而是会话是元数据,谁在乎呢。
        // ignore spring security session
    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
    
    @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);
        }
    }
    
        // ignore spring security session
    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);