@AuthenticationPrincipal オブジェクトは、セッションに保存された以前の値を返します。
スプリング ブート + スプリング セキュリティ oauth REST サーバー。https://github.com/legshort/spring-boot-sample
これら 2 つの 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() である 2 番目のリクエストにはセッション値があり、以前のテストを使用したのと同じユーザーです。そのため、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-security-oauth の実用的な例はありますか?
更新しました
mockMvc について私が理解している限りでは、すべての設定がクリアされ、 setUp() メソッドを使用して毎回ほとんど新しいモック サーバーが作成されます。したがって、アクセス トークン ストアは毎回クリアする必要がありますが、トークン ストアは認証されたトークンを維持します。
テスト中に省略した「/oauth/token」で要求されたアクセス トークンを要求すると、次のように InMemoryTokenStore が呼び出されます。
テスト プロセス ログ
testUpdateUser() -> POST: /oauth/token -> ストア トークン
トークン: 50b10897-9e15-4859-aeb0-43d0802ba42c
ユーザー: id=2testUpdateUser() -> PUT: /users/2 -> 読み取りトークン
token: 50b10897-9e15-4859-aeb0-43d0802ba42c
ユーザー: id=2testUpdateUserWithWrongUserId() -> GET: /oauth/token -> トークン
トークンを保存: 50b10897-9e15-4859-aeb0-43d0802ba42c -> 既にトークン
ユーザーに存在: id=2 -> id=4: ユーザーは新しいもので更新されましたtestUpdateUserWithWrongUserId() -> PUT: /users/0 -> 読み取りトークン
token: 50b10897-9e15-4859-aeb0-43d0802ba42c
ユーザー: id=2testDeleteUser() -> GET: /oauth/token -> トークンを保存するはずでしたが、トークンを保存しませんでした
testDeleteUser() -> DELETE: /users/5 -> read token
token: 50b10897-9e15-4859-aeb0-43d0802ba42c
user: id=2 -> userSignUp() で作成された id=5 であるはずのユーザー
質問
mockMvc を使用してすべてのテスト メソッドで InMemoryTokenStore をクリアするにはどうすればよいですか?