前言
最近遇到一個功能需要用戶可以自定義系統的密碼規則,傳統中對於密碼規則這塊一般都是後端給定常用的密碼正則表達式,然後當用戶註冊的時候填寫密碼,系統獲取密碼後會匹配這個給定的正則表達式,如果不匹配會提示用戶密碼不符合規範。
現在如果是可以自定義密碼規則,首先不太可能由用戶直接寫正則表達式,難度較大且正則表達式的正確性無法得到保證。通過分析一般密碼的正則表達式發現基本都是數字、大小寫字母、特殊字符以及規定密碼的長度,所以如果自定義規則的話不妨讓用戶可以自定義密碼中數字、大小寫這些字段的長度,然後系統讀取這些長度後生成一個正則表達式,然後就和傳統的密碼匹配一樣。
之前都是直接使用SpringBoot自帶的@Pattern註解,然後直接手動定死正則表達式,現在多了個正則表達式生成的過程,學到了一些東西,現進行簡單記錄。
參考鏈接
1. 密碼規則自定義:https://blog.csdn.net/socalabo/article/details/82924858
2. 正則表達式:
https://blog.csdn.net/s275287998/article/details/102488773
https://www.cnblogs.com/ryanace1988/p/11082961.html
https://www.runoob.com/regexp/regexp-syntax.html
3. 隨機生成密碼:
https://blog.csdn.net/hero_lxz/article/details/79754998
https://blog.csdn.net/Yuriey/article/details/82491122
實現過程
1.根據字段生成正則表達式
設置用戶可以自定義密碼的最小長度、最大長度、數字最小長度、大小寫字母最小長度、特殊符號的最小長度。然後根據每個字段拼接生成正則表達式。
至少1個數字:
(?=.*\d)
或者
(?=.*[0-9])
至少一個小寫字母:
(?=.*[a-z])
至少一個大寫字母:
(?=.*[A-Z])
至少一個特殊字符:此處列舉的是鍵盤上的除開數字字母的字符,有其他字符直接添加進去即可
(?=.*?[#?!@$%^&*-_])
但是實際中有時候出現至少兩位數字這種情況,所以進行改造:
以數字爲例,至少n位數字,以兩位爲例:其他大/小寫字母、特殊字符同數字
(?=.*[0-9].*[0-9])
根據獲取的密碼各字段長度,完成各部分正則表達式的構成,最後實現整體密碼正則表達式的拼接,舉例:至少2位數字、1位特殊字符,2位小寫字母,0位大寫字母,密碼長度至少爲6至多爲10
^(?=.*[0-9]*[0-9])(?=.*[a-z].*[a-z])(?=.*?[#?!@$%^&*-_]).{6,10}$
上述正則表達式不限定字符出現的順序,即只要保證密碼中有這些最小個數的字符即可。代碼實現中根據不同字段不同的長度分別進行拼接即可,此處不再贅述。
3. 密碼匹配
密碼匹配直接使用matches方法即可,或許用戶的密碼然後調用matches方法,方法參數爲生成的這個正則表達式即可
拓展
1. 隨機生成密碼
隨機生成密碼就是根據系統規則然後分別隨機取密碼的長度、各個字段的長度、各個類型字段在密碼中的位置、各個字段的具體值。
隨機使用Random類,Random中使用方法nextInt(n)方法獲取[0,n)範圍的隨機值,隨機生成密碼各部分的隨機可抽象出一個方法,根據上下限來獲取隨機的n
/**
* 隨機獲取一個指定範圍的數字 [0,max-min+1)+min=[min,max+1)=[min.max]
* @return
*/
public int getRandomInt(int min,int max){
return random.nextInt(max-min+1)+min;
}
大寫字母、小寫字母根據在ASCII中的編碼值確定隨機n,特殊字符在枚舉中的特殊字符中隨機下標取一個值即可,數字在0-9中取一個隨機值。
/**
* 隨機獲取一個特殊字符
*/
public String getRandomSpecialLetter(){
char[] chars = {'`', '~', '@', '#', '$', '%', '^', '&',
'*', '(', ')', '-', '_', '=', '+', '[',
'{', '}', ']', '\\', '|', ';', ':', '"',
'\'', ',', '<', '.', '>', '/', '?'};
return String.valueOf(chars[random.nextInt(chars.length)]); //數組的索引從0開始,random同
}
/**
* 隨機獲取一個0-9的數字
*/
public int getRandomDigit(){
return getRandomInt(0,9);
}
/**
* 隨機獲取一個大寫字母
*/
public char getRandomUpper(){
return (char)getRandomInt(65,90);
}
/**
* 隨機獲取一個小寫字母
* @return
*/
public char getRandomLower(){
return getRandomInt(97,122);
}
各字段密碼在整段密碼中的隨機位置,通過定義一個Map集合,然後隨機取下標賦字段值即可。
//定義隨機密碼中各字段在整個密碼的位置
Map<Integer,String> indexMap=new HashMap<Integer,String>();
while(indexMap.size()<upperNum){
//確定大寫字母在整段密碼中的索引號
int rint=getRandomInt(0, pwdLength-1);
if(indexMap.get(rint)==null){
indexMap.put(rint, "upper");
}
}
while(indexMap.size()<upperNum+lowerNum){
//確定小寫字母的索引號
int rint=getRandomInt(0, pwdLength-1);
if(indexMap.get(rint)==null){
indexMap.put(rint, "lower");
}
}
//...其他字段類似
2. 密碼加密
加密可以使用PasswordEncoder類,使用其encode方法,方法參數爲密碼,將密碼加密
知識點總結
1. 正則表達式
2. JSON與Java對象互轉
https://blog.csdn.net/qq_38586378/article/details/103001255
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.40</version>
</dependency>
ObjectMapper mapper = new ObjectMapper();
//Java轉JSON
String jsonStr = mapper.writeValueAsString(Object obj); //一般需要捕獲處理JsonProcessingException異常
//JSON轉Java
Object obj = mapper.readValue(jsonStr,Object.class)
總結
拿到功能先理用戶邏輯,然後將功能分步最後按步驟實現。