Spring項(xiàng)目使用Maven和BCrypt實(shí)現(xiàn)修改密碼功能方式
簡(jiǎn)介
在數(shù)字時(shí)代,信息安全的重要性不言而喻,尤其當(dāng)涉及到個(gè)人隱私和賬戶安全時(shí)。每天,無(wú)數(shù)的用戶登錄各種在線服務(wù),從社交媒體到銀行賬戶,再到電子郵件和云存儲(chǔ)服務(wù)。這些服務(wù)的背后,是復(fù)雜的系統(tǒng)架構(gòu),其中包含著用戶最為敏感的數(shù)據(jù)——密碼。
過(guò)去,簡(jiǎn)單的加密方法和弱密碼策略導(dǎo)致了許多嚴(yán)重的數(shù)據(jù)泄露事件。例如,2013年雅虎(Yahoo)遭遇的大規(guī)模數(shù)據(jù)泄露事件,影響了數(shù)十億的用戶賬戶,部分原因就是由于使用了不夠安全的密碼存儲(chǔ)技術(shù)。再如2016年的LinkedIn數(shù)據(jù)泄露事件,盡管該公司使用了SHA-1散列算法對(duì)密碼進(jìn)行了處理,但未加鹽的密碼散列最終還是被破解,暴露了用戶的隱私。
這些事件引發(fā)了行業(yè)對(duì)于密碼安全的深刻反思,促使開(kāi)發(fā)者和安全專家尋找更安全的解決方案。BCrypt作為一種適應(yīng)性強(qiáng)且經(jīng)過(guò)時(shí)間考驗(yàn)的密碼哈希算法,成為了現(xiàn)代密碼安全的基石。它不僅能夠有效抵御暴力破解和彩虹表攻擊,還能通過(guò)增加工作因子來(lái)適應(yīng)未來(lái)計(jì)算能力的增長(zhǎng)。
在本文中,我們將深入探討如何在Spring項(xiàng)目中利用Maven和BCrypt來(lái)實(shí)現(xiàn)一個(gè)安全的密碼修改功能。這不僅僅是關(guān)于代碼實(shí)現(xiàn)的問(wèn)題,更是一次對(duì)密碼安全重要性的重申,以及對(duì)如何在實(shí)際應(yīng)用中踐行這一原則的示范。我們將從環(huán)境搭建開(kāi)始,逐步構(gòu)建出一個(gè)既實(shí)用又安全的密碼修改流程,確保即使在最惡劣的情況下,用戶的密碼也能得到妥善保護(hù)。
通過(guò)本文的學(xué)習(xí),你將獲得寶貴的實(shí)踐經(jīng)驗(yàn),了解如何在自己的項(xiàng)目中實(shí)施類似的解決方案,從而提升應(yīng)用的安全性,給用戶提供更加安心的在線體驗(yàn)。在接下來(lái)的內(nèi)容中,我們將一步步解析實(shí)現(xiàn)過(guò)程,從添加依賴到編寫核心業(yè)務(wù)邏輯,直至完成完整的功能測(cè)試,確保每一步都遵循最佳的安全實(shí)踐。
controller(UserController)
/** * 修改密碼 */ @PutMapping("/update/pwd/{id}") public Result update(@PathVariable("id") long id, @RequestBody ChangePasswordVo changePasswordVo) { try{ userService.changePassword(changePasswordVo,id); return Result.success("修改成功!"); }catch (Exception e){ // 捕獲異常,獲取異常信息 String message = e.getMessage(); // 如果修改失敗,返回失敗的結(jié)果,并附帶異常信息 return Result.failed(message); } }
1.注解 @PutMapping("/update/pwd/{id}")
@PutMapping
是Spring MVC中的一個(gè)注解,用于處理HTTP PUT請(qǐng)求。"/update/pwd/{id}"
是該方法的URL路徑。其中{id}
是一個(gè)路徑變量,用于接收用戶ID。
2.方法定義 public Result update(...)
- 這是一個(gè)公開(kāi)的方法,名為
update
,返回一個(gè)Result
對(duì)象。 Result
很可能是一個(gè)自定義的響應(yīng)類,通常用于封裝API的響應(yīng)結(jié)果,包括狀態(tài)碼、消息和數(shù)據(jù)等。
3.方法參數(shù)
@PathVariable("id") long id
:這是從URL路徑中提取的id
變量。@PathVariable
注解告訴Spring MVC從URL中提取名為id
的變量值,并將其轉(zhuǎn)換為long
類型。@RequestBody ChangePasswordVo changePasswordVo
:@RequestBody
注解用于將HTTP請(qǐng)求體中的JSON數(shù)據(jù)轉(zhuǎn)換為ChangePasswordVo
類型的對(duì)象。ChangePasswordVo
可能是一個(gè)包含舊密碼和新密碼等信息的DTO(數(shù)據(jù)傳輸對(duì)象)。
4.方法體
- 首先,它嘗試調(diào)用
userService.changePassword(changePasswordVo,id);
。這里假設(shè)userService
是一個(gè)已經(jīng)注入的服務(wù)類,用于處理與用戶相關(guān)的業(yè)務(wù)邏輯。changePassword
方法可能會(huì)根據(jù)提供的用戶ID和密碼信息來(lái)更新用戶的密碼。 - 如果上述操作成功,方法將返回一個(gè)表示成功的
Result
對(duì)象,并附帶消息“修改成功!”。
如果在更新密碼的過(guò)程中發(fā)生異常(如數(shù)據(jù)庫(kù)錯(cuò)誤、密碼驗(yàn)證失敗等),catch
塊將捕獲該異常,并獲取其消息。然后,它返回一個(gè)表示失敗的Result
對(duì)象,并附帶異常的消息。
entity(VO-ChangePasswordVo)
@Data public class ChangePasswordVo implements Serializable { /** * 舊的密碼 */ private String oldpassword; /** * 新的密碼 */ private String newpassword; }
1.注解
@Data
: 這是一個(gè)Lombok庫(kù)提供的注解。當(dāng)你添加@Data
到類上時(shí),Lombok會(huì)自動(dòng)為這個(gè)類生成getter、setter、equals、hashCode和toString方法。這可以大大減少模板代碼的數(shù)量,使代碼更加簡(jiǎn)潔。implements Serializable
: 這表示該類實(shí)現(xiàn)了Serializable
接口。Serializable
是一個(gè)標(biāo)記接口,用于指示一個(gè)類的對(duì)象可以被序列化。序列化是將對(duì)象狀態(tài)轉(zhuǎn)換為字節(jié)流,以便可以將其寫入文件或發(fā)送到網(wǎng)絡(luò)上的另一個(gè)位置。如果該類或其成員類(如果它們不是基本類型或String
、數(shù)組
等)需要被序列化,則必須實(shí)現(xiàn)這個(gè)接口。
2.成員變量
private String oldpassword;
: 這是一個(gè)私有字符串類型的成員變量,用于存儲(chǔ)舊的密碼。但是,從Java的命名約定來(lái)看,變量名應(yīng)該使用駝峰命名法(camelCase),并且首字母小寫。因此,更合適的命名可能是oldPassword
。private String newpassword;
: 同樣,這是一個(gè)私有字符串類型的成員變量,用于存儲(chǔ)新的密碼。按照J(rèn)ava的命名約定,它應(yīng)該被命名為newPassword
。
3.注釋
- 每個(gè)成員變量上方都有注釋,描述了該變量的用途。
- 這是一個(gè)很好的做法,因?yàn)樗黾恿舜a的可讀性。
- 但是,請(qǐng)注意,這些注釋是用中文寫的,而在國(guó)際項(xiàng)目中,通常建議使用英文注釋。
Service
UserService
void changePassword(ChangePasswordVo changePasswordVo, Long id);
1.返回類型 (void
): 方法前面有一個(gè)void
關(guān)鍵字,表示這個(gè)方法沒(méi)有返回值。也就是說(shuō),當(dāng)你調(diào)用這個(gè)方法時(shí),它不會(huì)返回任何值或?qū)ο蟆?/p>
2.方法名 (changePassword
): 這是方法的名稱,即changePassword
。當(dāng)你想在代碼的其他部分調(diào)用這個(gè)方法時(shí),你會(huì)使用這個(gè)名字。
參數(shù):
ChangePasswordVo changePasswordVo
: 這是方法的第一個(gè)參數(shù)。
ChangePasswordVo
: 這是參數(shù)的類型。它可能是一個(gè)數(shù)據(jù)傳輸對(duì)象(DTO),用于封裝與更改密碼相關(guān)的數(shù)據(jù),如舊密碼、新密碼等。changePasswordVo
: 這是參數(shù)的名稱。在方法內(nèi)部,你可以使用這個(gè)名稱來(lái)引用傳入的ChangePasswordVo
對(duì)象。
Long id
: 這是方法的第二個(gè)參數(shù)。
Long
: 這是參數(shù)的類型,表示這是一個(gè)長(zhǎng)整型(64位整數(shù))數(shù)據(jù)。id
: 這是參數(shù)的名稱。在方法內(nèi)部,你可以使用這個(gè)名稱來(lái)引用傳入的id
值。從參數(shù)名可以推測(cè),這個(gè)id
可能表示用戶的唯一標(biāo)識(shí)符(如用戶ID)。
UserServiceImpl
@Override public void changePassword(ChangePasswordVo changePasswordVo, Long id){ // 根據(jù)id查詢用戶信息 User user = userMapper.selectById(id); // 判斷原密碼是否正確 if(!BCrypt.checkpw(changePasswordVo.getOldpassword(),user.getPassword())){ throw new RuntimeException("原密碼不正確"); } // 設(shè)置新密碼 user.setPassword(BCrypt.hashpw(changePasswordVo.getNewpassword(), BCrypt.gensalt())); // 調(diào)用Mapper的updateById方法更新用戶信息 userMapper.updateById(user); }
1.@Override:
- 這是一個(gè)Java注解,它告訴編譯器這個(gè)方法是從超類或接口中繼承或?qū)崿F(xiàn)的。
- 使用
@Override
注解可以確保你正確地重寫了父類或接口中的方法,如果沒(méi)有正確重寫(例如方法簽名不匹配),編譯器會(huì)報(bào)錯(cuò)。
2.public void changePassword(ChangePasswordVo changePasswordVo, Long id): 這是方法的聲明部分。
public
:表示這是一個(gè)公共方法,可以從任何其他類中被訪問(wèn)。void
:表示該方法沒(méi)有返回值。changePassword
:是方法的名稱。ChangePasswordVo changePasswordVo
和Long id
:是方法的參數(shù)。ChangePasswordVo
可能是一個(gè)數(shù)據(jù)傳輸對(duì)象(DTO),用于封裝密碼更改請(qǐng)求所需的信息(如舊密碼和新密碼)。id
則是用戶的唯一標(biāo)識(shí)符。
3.User user = userMapper.selectById(id);:
- 使用
userMapper
(可能是MyBatis的Mapper或類似的ORM工具)的selectById
方法根據(jù)提供的id
從數(shù)據(jù)庫(kù)中查詢用戶信息,并將查詢到的用戶信息存儲(chǔ)在user
變量中。
4.if(!BCrypt.checkpw(changePasswordVo.getOldpassword(),user.getPassword())){:
- 使用
BCrypt
庫(kù)(一個(gè)流行的密碼哈希庫(kù))的checkpw
方法檢查用戶提供的舊密碼(從changePasswordVo
中獲取)是否與數(shù)據(jù)庫(kù)中存儲(chǔ)的哈希密碼(從查詢到的user
對(duì)象中獲?。┢ヅ洹?/li> - 如果不匹配(
!BCrypt.checkpw(...)
返回true
),則執(zhí)行下面的throw
語(yǔ)句。
5.throw new RuntimeException("原密碼不正確");:
- 如果舊密碼不正確,則拋出一個(gè)
RuntimeException
,并帶有消息“原密碼不正確”。調(diào)用此方法的代碼應(yīng)該捕獲此異常并適當(dāng)?shù)靥幚硭ɡ?,向用戶顯示錯(cuò)誤消息)。
6.user.setPassword(BCrypt.hashpw(changePasswordVo.getNewpassword(), BCrypt.gensalt()));:
- 如果舊密碼正確,則使用
BCrypt
庫(kù)的gensalt
方法生成一個(gè)新的隨機(jī)鹽值。 - 使用這個(gè)新鹽值和用戶提供的新密碼(從
changePasswordVo
中獲取)作為參數(shù),調(diào)用BCrypt
的hashpw
方法生成新的哈希密碼。 - 將這個(gè)新的哈希密碼設(shè)置到
user
對(duì)象的password
字段中。
7.userMapper.updateById(user);:
- 使用
userMapper
的updateById
方法更新數(shù)據(jù)庫(kù)中對(duì)應(yīng)id
的用戶的密碼信息。 - 這里假設(shè)
userMapper
的updateById
方法會(huì)處理將user
對(duì)象中的更改保存到數(shù)據(jù)庫(kù)中的邏輯。
測(cè)試
先新增一條數(shù)據(jù)
密碼:111
進(jìn)行修改密碼;
id為你新增后的id號(hào)
輸入字段為我之前定義的字段oldpassword與newpassword
可以看到密碼已經(jīng)被修改
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- 解決Spring security5.5.7報(bào)錯(cuò)Encoded password does not look like BCrypt異常
- 使用spring?security?BCryptPasswordEncoder接入系統(tǒng)
- 如何在spring boot項(xiàng)目中使用Spring Security的BCryptPasswordEncoder類進(jìn)行相同密碼不同密文的加密和驗(yàn)證
- 一文掌握SpringSecurity?BCrypt密碼加密和解密
- Springboot基于BCrypt非對(duì)稱加密字符串的實(shí)現(xiàn)
- SpringBoot整合BCrypt實(shí)現(xiàn)密碼加密
- Spring security BCryptPasswordEncoder密碼驗(yàn)證原理詳解
相關(guān)文章
SpringMVC中的請(qǐng)求參數(shù)接收方式
這篇文章主要介紹了SpringMVC中的請(qǐng)求參數(shù)接收方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-04-04Java JDK動(dòng)態(tài)代理(AOP)用法及實(shí)現(xiàn)原理詳解
在本篇文章了小編給大家整理的是一篇關(guān)于Java JDK動(dòng)態(tài)代理(AOP)用法及實(shí)現(xiàn)原理詳解內(nèi)容,有需要的朋友們可以參考學(xué)習(xí)下。2020-10-10Java實(shí)現(xiàn)AES加密算法的簡(jiǎn)單示例分享
這篇文章主要介紹了Java實(shí)現(xiàn)AES加密算法的簡(jiǎn)單示例分享,AES算法是基于對(duì)密碼值的置換和替代,需要的朋友可以參考下2016-04-04java實(shí)現(xiàn)字符串和日期類型相互轉(zhuǎn)換的方法
這篇文章主要介紹了java實(shí)現(xiàn)字符串和日期類型相互轉(zhuǎn)換的方法,涉及java針對(duì)日期與字符串的轉(zhuǎn)換與運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2017-02-02Java中冒泡排序的原生實(shí)現(xiàn)方法(正序與逆序)
這篇文章主要給大家介紹了關(guān)于Java中冒泡排序的原生實(shí)現(xiàn)方法(正序與逆序)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11Java隨手筆記8之包、環(huán)境變量和訪問(wèn)控制及maven profile實(shí)現(xiàn)多環(huán)境打包
這篇文章主要介紹了Java隨手筆記8之包、環(huán)境變量和訪問(wèn)控制及maven profile實(shí)現(xiàn)多環(huán)境打包的相關(guān)資料,需要的朋友可以參考下2015-11-11mybatis-plus3.0.1枚舉返回為null解決辦法
這篇文章主要介紹了mybatis-plus3.0.1枚舉返回為null解決辦法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12