1. 概要

この簡単な記事では、ユーザーが登録してログインした後に利用できる簡単な「自分のパスワードを変更する」機能を実装します。

2. クライアント側–パスワードページの変更

非常に単純なクライアント側のページを見てみましょう。

<html>
<body>
<div id="errormsg" style="display:none"></div>
<div>
    <input id="oldpass" name="oldpassword" type="password" />
    <input id="pass" name="password" type="password" />
    <input id="passConfirm" type="password" />              
    <span id="error" style="display:none">Password mismatch</span>
                    
   <button type="submit" onclick="savePass()">Change Password</button>
</div>
 
<script src="jquery.min.js"></script>
<script type="text/javascript">

var serverContext = [[@{/}]];
function savePass(){
    var pass = $("#pass").val();
    var valid = pass == $("#passConfirm").val();
    if(!valid) {
      $("#error").show();
      return;
    }
    $.post(serverContext + "user/updatePassword",
      {password: pass, oldpassword: $("#oldpass").val()} ,function(data){
        window.location.href = serverContext +"/home.html?message="+data.message;
    })
    .fail(function(data) {
        $("#errormsg").show().html(data.responseJSON.message);
    });
}
</script> 
</body>
</html>

3. ユーザーパスワードの更新

サーバー側の操作も実装しましょう。

@PostMapping("/user/updatePassword")
@PreAuthorize("hasRole('READ_PRIVILEGE')")
public GenericResponse changeUserPassword(Locale locale, 
  @RequestParam("password") String password, 
  @RequestParam("oldpassword") String oldPassword) {
    User user = userService.findUserByEmail(
      SecurityContextHolder.getContext().getAuthentication().getName());
    
    if (!userService.checkIfValidOldPassword(user, oldPassword)) {
        throw new InvalidOldPasswordException();
    }
    userService.changeUserPassword(user, password);
    return new GenericResponse(messages.getMessage("message.updatePasswordSuc", null, locale));
}

メソッドは@PreAuthorizeアノテーションを介して保護されていることに注意してください。これは、ログインしているユーザーのみがアクセスできる必要があるためです。

4. APIテスト

最後に、すべてが正常に機能していることを確認するために、いくつかのAPIテストでAPIを使用してみましょう。 テストの簡単な構成とデータの初期化から始めます。

@ExtendWith(SpringExtension.class)
@ContextConfiguration(
  classes = { ConfigTest.class, PersistenceJPAConfig.class }, 
  loader = AnnotationConfigContextLoader.class)
public class ChangePasswordApiTest {
    private final String URL_PREFIX = "http://localhost:8080/"; 
    private final String URL = URL_PREFIX + "/user/updatePassword";
    
    @Autowired
    private UserRepository userRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    FormAuthConfig formConfig = new FormAuthConfig(
      URL_PREFIX + "/login", "username", "password");

    @BeforeEach
    public void init() {
        User user = userRepository.findByEmail("[email protected]");
        if (user == null) {
            user = new User();
            user.setFirstName("Test");
            user.setLastName("Test");
            user.setPassword(passwordEncoder.encode("test"));
            user.setEmail("[email protected]");
            user.setEnabled(true);
            userRepository.save(user);
        } else {
            user.setPassword(passwordEncoder.encode("test"));
            userRepository.save(user);
        }
    }
}

では、ログインユーザーのパスワードを変更してみましょう

@Test
public void givenLoggedInUser_whenChangingPassword_thenCorrect() {
    RequestSpecification request = RestAssured.given().auth()
      .form("[email protected]", "test", formConfig);

    Map<String, String> params = new HashMap<String, String>();
    params.put("oldpassword", "test");
    params.put("password", "newtest");

    Response response = request.with().params(params).post(URL);

    assertEquals(200, response.statusCode());
    assertTrue(response.body().asString().contains("Password updated successfully"));
}

次へ–間違った古いパスワードを指定して、パスワードを変更してみましょう。

@Test
public void givenWrongOldPassword_whenChangingPassword_thenBadRequest() {
    RequestSpecification request = RestAssured.given().auth()
      .form("[email protected]", "test", formConfig);

    Map<String, String> params = new HashMap<String, String>();
    params.put("oldpassword", "abc");
    params.put("password", "newtest");

    Response response = request.with().params(params).post(URL);

    assertEquals(400, response.statusCode());
    assertTrue(response.body().asString().contains("Invalid Old Password"));
}

最後に、認証なしでパスワードを変更してみましょう

@Test
public void givenNotAuthenticatedUser_whenChangingPassword_thenRedirect() {
    Map<String, String> params = new HashMap<String, String>();
    params.put("oldpassword", "abc");
    params.put("password", "xyz");

    Response response = RestAssured.with().params(params).post(URL);

    assertEquals(302, response.statusCode());
    assertFalse(response.body().asString().contains("Password updated successfully"));
}

各テストで、認証を処理するためのFormAuthConfigを提供していることに注意してください。

また、 init()を使用してパスワードをリセットし、テスト前に正しいパスワードを使用していることを確認します。

5. 結論

これで終わりです。ユーザーがアプリケーションに登録してログインした後、自分のパスワードを変更できるようにする簡単な方法です。

このチュートリアルの完全実装は、 githubプロジェクトにあります。これはEclipseベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。