、Mybatis.xml
<update id="changePassword" parameterType="string">
<!--id要與抽象方法的方法名保持一致,否則會報錯 -->
UPDATE user
SET
<if test="password!=null">
password=#{password}
</if>
WHERE id=#{id}
</update>
二、Mapper
//修改密碼
public int changePassword(String password,Integer id);
三、Service
//修改密碼
public int changePassword(String new_password,Integer id) throws Exception{
int res=userMapper.changePassword(new_password,id);
return res;
}
四、Controller
這里面使用Shiro獲取登錄用戶信息,使用CryptographyUtil.md5進行加密。
//修改密碼
@ResponseBody
@RequestMapping("/changepassword")
public JSONObject changePassword1(String old_password, String new_password) throws Exception{
JSONObject result = new JSONObject();
//根據用戶id查詢到用戶的信息
User user = (User) SecurityUtils.getSubject().getSession().getAttribute("currentUser");
if (user!=null){
String md5password = CryptographyUtil.md5(old_password, "java");
if (user.getPassword().equals(md5password)){
String newmd5 =CryptographyUtil.md5(new_password,"java");
System.out.println(newmd5);
int res=userService.changePassword(newmd5,user.getId());
result.put("success", true);
result.put("msg", "修改成功");
}else {
result.put("success", false);
result.put("msg", "原密碼不正確!");
}
}else {
result.put("success", false);
result.put("msg", "用戶名未找到!");
}
return result;
}
五、前端
線演示1
本地下載
在今天的jQuery教程中,我們將介紹如何使用jQuery和其它相關的插件來生成一個漂亮的帶有密碼強度檢驗的注冊頁面,希望大家喜歡!
相關的插件和類庫
complexify- 一個密碼強度檢驗jQuery插件
justgage- 一個兼容性良好的儀表盤類庫
主要功能
注冊中包含一個密碼強度檢驗組件,用戶需要設置一定強度的密碼才可以注冊
密碼強度使用儀表盤類庫justgage來顯示,不同的強度的密碼將顯示不同的顏色
密碼強度符合要求后,顯示注冊按鈕
代碼說明
HTML:
<div id="page-wrap"><div id="title">注冊新賬號 - gbtags.com</div><p><input type="text" name="email" id="email" placeholder="電子郵件"/></p><p><input type="password" name="password" id="password" placeholder="輸入密碼"/></p><div id="complexity"></div><p><input type="button" name="submit" id="submit" value="注冊" /></p><p id="msgbox"></p></div>
添加電子郵件和密碼輸入框,及其密碼強度組件。
Javascript:
導入所需的類庫,包括:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script><script src="js/jquery.complexify.js"></script><script src="js/jquery.placeholder.min.js"></script><script src="js/raphael.2.1.0.min.js"></script><script src="js/justgage.1.0.1.min.js"></script>
以下為生成儀表盤及其密碼強度代碼:
$(function(){$('#submit').attr('disabled', true);var g1 = new JustGage({ id: "complexity", value: 0, min: 0, max: 100, title: "密碼強度提示", titleFontColor: '#9d7540', valueFontColor : '#CCCCCC', label: "points",levelColors: [ "#dfa65a", "#926d3b", "#584224"] ?});$('input[placeholder]').placeholder();$("#password").complexify({}, function(valid, complexity){if(valid){$('#submit').fadeIn();}else{$('#submit').fadeOut();}g1.refresh(Math.round(complexity));});$('#submit').click(function(){$('#msgbox').html('welcome to gbtags.com');});});
以上代碼中,我們使用JustGage生成需要的儀表盤。相關選項請參考代碼。
以下代碼中,我們使用complexify的回調方法來判斷用戶輸入的密碼強度是否符合要求:
$("#password").complexify({}, function(valid, complexity){if(valid){$('#submit').fadeIn();}else{$('#submit').fadeOut();}g1.refresh(Math.round(complexity));});
如果符合則顯示注冊按鈕,否則隱藏。同時刷新儀表盤的數值和顏色。
CSS代碼:
body{background: url('../images/body.png');}#container{background: url('../images/bg.jpg');padding: 30px;margin-top: 150px;box-shadow: 0px 0px 30px #9d7540;border-radius: 5px 5px 0px 0px;}#page-wrap{margin: 0 auto;width: 310px;text-align: center;font-size: 14px;padding:0px;font-family: Arial;}P{margin: 20px 0;padding:0;}#title{width: 292px;margin: 20px 0;font-size: 14px;font-weight: normal;font-family: Arial;color: #a27942;text-align:left;border-left: 4px solid #6e522d;border-right: 6px solid #303030;border-radius: 5px;padding: 12px 5px;background: #303030;box-shadow: 0px 0px 10px #4f3b20;}#msgbox{color: #808080;}input{width: 300px;height: 40px;box-shadow: 0px 0px 10px #4f3b20;border-radius: 5px;font-size: 14px;font-weight: normal;margin:0;padding: 0 5px;border: 1px solid #606060;font-family: Arial;background: #303030;color: #CCC;}#complexity{width: 302px;padding: 5px 5px;font-size: 18px;font-weight: bold;margin: 0px;box-shadow: 0px 0px 10px #4f3b20;border-radius: 5px;color:#CCC;background: #303030;}#submit{display: none;width: 310px;}#gbin1{padding: 15px 0px;text-align: center;background: #101010;color: #909090;font-size:12px;font-family: Arial;border-radius: 0px 0px 5px 5px;box-shadow: 0px 0px 20px #4f3b20;}#gbin1 a{font-family: Arial;font-size:12px;color: #909090;text-shadow: 1px 1px 25px #fff;text-decoration: none;}
代碼書寫完畢,如果需要查看完整代碼,請下載演示。希望大家喜歡這個實現!如果你有任何意見和建議請給我們留言,謝謝!
原文鏈接:http://www.gbtags.com/gb/share/5889.htm
pring Security的PasswordEncoder接口用于執行密碼單向的轉換,以允許安全地存儲密碼。假定PasswordEncoder是單向轉換,那么當密碼轉換需要雙向轉換時(例如,存儲用于向數據庫進行身份驗證的憑證),就不需要使用它。通常,PasswordEncoder用于存儲需要在身份驗證時與用戶提供的密碼進行比較的密碼。
經過多年的發展,存儲密碼的標準機制已經形成。一開始密碼是以明文形式存儲的。密碼被認為是安全的,因為數據存儲的密碼保存在訪問它所需的憑證中。然而,惡意用戶能夠通過使用SQL注入等攻擊找到獲取大量用戶名和密碼“轉儲”的方法。隨著越來越多的用戶憑證成為公共安全事件,專家意識到我們需要做更多的工作來保護用戶的密碼。
然后,開發人員被鼓勵通過單向哈希(例如SHA-256)來存儲密碼。當用戶試圖進行身份驗證時,將哈希密碼與他們鍵入的密碼的哈希進行比較。這意味著系統只需要存儲密碼的單向哈希。如果發生了入侵,那么只有密碼哈希被暴露了。由于哈希是一種算法,而且根據哈希來猜測密碼在計算上非常困難,因此不值得花力氣去找出系統中的每個密碼。為了破解這種方式,惡意用戶決定創建稱為彩虹表(https://en.wikipedia.org/wiki/Rainbow_table)的查找表。他們不是每次都猜測每個密碼,而是計算一次密碼并將其存儲在一個查找表中。
為了降低彩虹表的有效性,開發者被鼓勵使用鹽值密碼。與僅僅使用密碼作為哈希函數的輸入不同,它將為每個用戶的密碼生成隨機字節(稱為鹽值)。鹽值和用戶密碼將通過哈希函數運行,該函數生成一個唯一的鹽值。鹽值將以明文形式與用戶密碼一起存儲。然后,當用戶試圖進行身份驗證時,將哈希密碼與存儲的鹽值的哈希值和用戶輸入的密碼進行比較。獨特的鹽值意味著彩虹表不再有效,因為每種鹽值和密碼組合的哈希值是不同的。
在現代,我們意識到加密散列(如SHA-256)不再安全。原因是,用現代硬件,我們可以在一秒鐘內執行數十億次哈希計算。這意味著我們可以輕松地破解每個密碼。
現在鼓勵開發人員利用自適應單向函數來存儲密碼。使用自適應單向函數進行密碼驗證是有意的資源密集型(即CPU、內存等)。一個自適應單向函數允許配置一個“工作因子”,它可以隨著硬件變得更好而增長。建議將“工作因子”調整為在您的系統上花費大約1秒的時間來驗證密碼。這樣做的好處是讓攻擊者很難破解密碼,但又不至于讓自己的系統負擔過重。Spring Security試圖為“工作因子”提供一個良好的起點,但是鼓勵用戶為自己的系統定制“工作因子”,因為不同系統的性能會有很大的不同。應該使用的自適應單向函數示例包括bcrypt、PBKDF2、scrypt和argon2。
由于自適應單向函數有意地需要大量資源,因此為每個請求驗證用戶名和密碼將顯著降低應用程序的性能。Spring Security(或任何其他庫)都無法加速密碼的驗證,因為安全性是通過密集的驗證資源來獲得的。鼓勵用戶交換長期憑證(如用戶名和密碼)為短期憑據(如會話,OAuth令牌,等)。可以快速驗證短期憑證,而不會損失任何安全性。
在Spring Security 5.0之前,默認的PasswordEncoder是NoOpPasswordEncoder,它需要純文本密碼。根據密碼歷史部分,您可能認為默認的PasswordEncoder現在類似于BCryptPasswordEncoder。
然而,這忽略了三個現實問題:
Spring Security引入了DelegatingPasswordEncoder,它通過以下方式解決了所有問題:
您可以使用PasswordEncoderFactories輕松地構造DelegatingPasswordEncoder的實例。
示例:創建默認DelegatingPasswordEncoder
PasswordEncoder passwordEncoder =
PasswordEncoderFactories.createDelegatingPasswordEncoder();
或者,您可以創建自己的自定義實例。例如:
創建自定義DelegatingPasswordEncoder
String idForEncode = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(idForEncode, new BCryptPasswordEncoder());
encoders.put("noop", NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("sha256", new StandardPasswordEncoder());
PasswordEncoder passwordEncoder =
new DelegatingPasswordEncoder(idForEncode, encoders);
密碼的一般格式為:
DelegatingPasswordEncoder存儲格式
{id}encodedPassword
這樣,id是用于查找應該使用哪個PasswordEncoder的標識符,而encodedPassword是所選PasswordEncoder的原始編碼密碼。id必須在密碼的開頭,以{開始,以}結束。如果找不到id,則id為null。例如,下面可能是使用不同id編碼的密碼列表。所有的原始密碼都是“password”。
示例:DelegatingPasswordEncoder編碼密碼示例
{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
{noop}password
{pbkdf2}5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc
{scrypt}$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=
{sha256}97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0
一些用戶可能會擔心存儲格式是為潛在的黑客提供的。這不是一個問題,因為密碼的存儲并不依賴于算法是秘密的。此外,對于攻擊者來說,如果沒有前綴,大多數格式都很容易識別。例如,BCrypt密碼通常以a$開頭。
密碼編碼
傳入構造函數的idForEncode確定了將使用哪個PasswordEncoder對密碼進行編碼。在我們上面構造的DelegatingPasswordEncoder中,這意味著編碼密碼的結果將被委托給BCryptPasswordEncoder,并以{bcrypt}作為前綴。
最終結果如下:
DelegatingPasswordEncoder編碼的例子
{bcrypt}a$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
密碼匹配
匹配是基于{id}和id到構造函數中提供的PasswordEncoder的映射來完成的。我們的密碼存儲格式示例提供了如何實現此功能的示例。默認情況下,調用帶有密碼和沒有映射的id(包括null id)的匹配(CharSequence, String)的結果將導致IllegalArgumentException。可以使用DelegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(PasswordEncoder)自定義此行為。
通過使用id,我們可以匹配任何密碼編碼,但是使用最現代的密碼編碼編碼密碼。這一點很重要,因為與加密不同,密碼哈希被設計成沒有簡單的方法來恢復明文。由于沒有辦法恢復明文,這使得遷移密碼變得困難。雖然遷移NoOpPasswordEncoder對用戶來說很簡單,但我們選擇在默認情況下包含它,以簡化入門體驗。
開始體驗
如果您正在制作一個演示或示例,那么花時間對用戶的密碼進行哈希會有點麻煩。有一些方便的機制可以使這變得更容易,但這仍然不是用于生產的。
示例:withDefaultPasswordEncoder
User user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("user")
.build();
System.out.println(user.getPassword());
// {bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
如果要創建多個用戶,還可以重用構建器。
示例:withdefaultpasswordencoder重用構建器
UserBuilder users = User.withDefaultPasswordEncoder();
User user = users
.username("user")
.password("password")
.roles("USER")
.build();
User admin = users
.username("admin")
.password("password")
.roles("USER","ADMIN")
.build();
這將哈希存儲的密碼,但密碼仍然暴露在內存和已編譯的源代碼中。
因此,對于生產環境來說,它仍然不安全。對于生產,您應該在外部散列您的密碼。
用Spring Boot CLI編碼
正確編碼密碼的最簡單方法是使用Spring Boot CLI(https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-cli.html)。
例如,下面的代碼將對password的密碼進行編碼,以便與DelegatingPasswordEncoder一起使用:
Spring Boot CLI 編碼密碼使用實例
spring encodepassword password
{bcrypt}$2a$10$X5wFBtLrL/kHcmrOGGTrGufsBX8CJ0WpQpF3pgeuxBB/H73BK1DW6
故障排除
當存儲的其中一個密碼不具有密碼存儲格式中描述的id時,會發生以下錯誤。
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
at org.springframework.security.crypto.password.DelegatingPasswordEncoder$UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:233)
at org.springframework.security.crypto.password.DelegatingPasswordEncoder.matches(DelegatingPasswordEncoder.java:196)
解決該錯誤的最簡單方法是切換到顯式提供編碼密碼的PasswordEncoder。解決這個問題最簡單的方法是找出你的密碼目前是如何被存儲的,并明確地提供正確的密碼編碼器。
如果您從Spring Security 4.2.x遷移。您可以通過公開的NoOpPasswordEncoder bean恢復到以前的行為。
或者,您可以使用正確的id作為所有密碼的前綴,并繼續使用DelegatingPasswordEncoder。例如,如果你正在使用BCrypt,你會遷移你的密碼從一些類似:
a$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
到
{bcrypt}a$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
有關映射的完整列表,請參考PasswordEncoderFactories上的Javadoc(https://docs.spring.io/spring-security/site/docs/5.0.x/api/org/springframework/security/crypto/factory/PasswordEncoderFactories.html)。
BCryptPasswordEncoder實現使用廣泛支持的bcrypt算法對密碼進行哈希。為了使其更能抵抗密碼破解,bcrypt故意放慢速度。與其他自適應單向函數一樣,應該將其調整為在系統上花費大約1秒的時間驗證密碼。BCryptPasswordEncoder的默認實現使用強度10。建議您在自己的系統上調優和測試強度參數,以便驗證密碼大約需要1秒。
示例:BCryptPasswordEncoder
// Create an encoder with strength 16
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16);
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
Argon2PasswordEncoder實現使用Argon2(https://en.wikipedia.org/wiki/Argon2)算法對密碼進行哈希。Argon2是密碼哈希競賽的獲勝者(https://en.wikipedia.org/wiki/Password_Hashing_Competition)。為了在自定義硬件上破解密碼,Argon2是一個需要大量內存的緩慢算法。與其他自適應單向函數一樣,應該將其調整為在系統上花費大約1秒的時間驗證密碼。Argon2PasswordEncoder的當前實現需要BouncyCastle。
示例:Argon2PasswordEncoder
// Create an encoder with all the defaults
Argon2PasswordEncoder encoder = new Argon2PasswordEncoder();
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
Pbkdf2PasswordEncoder實現使用PBKDF2(https://en.wikipedia.org/wiki/PBKDF2)算法對密碼進行哈希。阻止密碼破解的,PBKDF2是一種故意很慢的算法。與其他自適應單向函數一樣,應該將其調整為在系統上花費大約1秒的時間驗證密碼。當需要FIPS認證時,這種算法是一個很好的選擇。
示例:Pbkdf2PasswordEncoder
// Create an encoder with all the defaults
Pbkdf2PasswordEncoder encoder = new Pbkdf2PasswordEncoder();
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
SCryptPasswordEncoder實現使用scrypt(https://en.wikipedia.org/wiki/Scrypt)算法對密碼進行哈希。為了阻止在定制硬件scrypt上的密碼破解,這是一個故意慢的算法,需要大量的內存。與其他自適應單向函數一樣,應該將其調整為在系統上花費大約1秒的時間驗證密碼。
示例:SCryptPasswordEncoder
// Create an encoder with all the defaults
SCryptPasswordEncoder encoder = new SCryptPasswordEncoder();
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
還有很多其他的PasswordEncoder實現完全是為了向后兼容而存在的。它們都已棄用,以表明它們不再被認為是安全的。然而,由于很難遷移現有的遺留系統,因此沒有刪除它們的計劃。
Spring Security默認使用DelegatingPasswordEncoder。但是,這可以通過將PasswordEncoder公開為Spring bean來進行定制。
如果您從Spring Security 4.2.x遷移。您可以通過公開NoOpPasswordEncoder bean恢復到以前的行為。
恢復到NoOpPasswordEncoder被認為是不安全的。相反,您應該遷移到使用DelegatingPasswordEncoder來支持安全的密碼編碼。
示例:NoOpPasswordEncoder
@Bean
public static NoOpPasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
XML配置要求NoOpPasswordEncoder bean名稱為passwordEncoder。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。