<div>
<a class="article-series-header" href="javascript:void(0);">該文章是系列的一部分</a>
<div>
<div>
• Spring Security 註冊系列
<br>
• 使用 Spring Security 的註冊流程
<br>
• 通過電子郵件激活新賬户
<br>
• Spring Security 註冊 – 發送驗證郵件
<br>
• 使用 Spring Security 註冊 – 密碼編碼
<br>
• 註冊 API 變為 RESTful
<br>
• Spring Security – 重置密碼
<br>
• 註冊 – 密碼強度和規則
<br>
<div>
• 更新密碼(當前文章)
</div>
• 通知用户從新設備或位置登錄
<br>
<div/>
</div>
<!-- end of article series inner -->
</div/>
<!-- .article-series-links -->
</div/>
<!-- end of article series section -->
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 Tests
最後,我們使用一些 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. 結論
這就是全部 – 這種簡單直接的方式允許用户在註冊並登錄應用程序後更改自己的密碼。
下一頁 »
通知用户從新設備或新位置登錄
« 上一頁
註冊 – 密碼強度與規則