本文最后更新于 2023年9月17日 上午
前言 如今,用户在网络上越来越重视个人隐私和信息安全,抛开服务提供商的问题,我们用户端,设置一个好的用户名和密码很重要。 这个时候,就需要设置一个强密码,用于避免非法用户”撞库“。同时,应该尽可能设置不同的密码。那么?如何生成随机的强密码呢?如何系统检测用户的密码是否强呢?
强密码 首先,我们明确强密码的组成🤔:
包含数字、大小写字母和特殊符号
尽量减少重复字符
尽量避免连续字符
之后,我们要考虑如何生成随机字符:
接下来,我们就使用代码实现上述需求:Python,使用的库函数为:
re:Python的标准库内容,使代码可以使用正则表达式 。
random:Python的标准库内容,使代码可以调用随机数相关的内容。
其他语言,如:Java、C++等均有类似库/外部包支持正则表达式和随机数,可以按本文思路覆写。
正则判断 如何判断字符串是否为强密码呢?第一步当然是判断是否包含数字和大小写字母以及特殊字符了 ,而判断这些内容,当时用正则表达式比较好。
为什么用正则 为什么我会引用正则表达式?主要原因:
极大程度 精简代码
正则规则,很容易判断字符串是否符合密码规则
举个例子,我需要判断字符串内字符是否有数字 ,可能的Python代码为(不使用正则表达式):
1 2 3 4 5 6 7 8 9 10 11 12 def is_number (s ): try : float (s) return True except ValueError: pass return False def toWords (s ): for i in s: if is_number(i): print ("包含数字:" +i)
而使用正则表达式就很简单了:
1 2 import re re.findall(r'\d' ,str )
可以看到,这精简程度,应该是有目共睹了。 如果你之前没接触正则表达式 ,可以看我这篇文章:
匹配数字 所以,匹配数字:
1 2 3 4 5 6 def hasNumber (pwd ): if (re.search(r'\d' , pwd)): return True else : return False
使用search 方法,判断是否含有数字类型。
匹配英文 匹配英文,也很简单:
1 2 3 4 5 6 7 8 9 10 11 12 13 def hasLowLetter (pwd ): if (re.search(r'[a-z]' , pwd)): return True else : return False def hasUpPLetter (pwd ): if (re.search(r'[A-Z]' , pwd)): return True else : return False
匹配特殊字符 匹配特殊字符,这边有一点点“脑筋急转弯”,首先,我们肯定知道\w
是指代英文和数字 ,那么\W
就是非英文和非数字,也就是特殊字符了。
1 2 3 4 5 6 def hasSpecial (pwd ): if (re.search(r'\W' , pwd)): return True else : return False
字符逻辑 正则判断,并不能判断字符逻辑,强密码的二三步:
进而避免出现:
1 2 3 aaBBcc@@ aaBBcc!! ABCabc!!
这样的密码出现,我们需要对生成的密码进行进一步的逻辑判断。这些判断,上文的正则判断 无法直接处理,需要我们用逻辑代码进行进一步的生成和处理。
连续字符判断 连续字符判断,其实是很简单的。主要有两个思路:
使用字符的Unicode编码 ,判断是否为连续字符
将字符转换为Ascii值 ,判断字符的Ascii值 是否连续
在Python内,可以使用chr()和ord()函数方法来实现:
chr()
:将字符转码为ascii编码返回(Python3中,转码为十进制Unicode编码返回)
ord()
:将十进制编码编译为字符
比如:
1 2 3 4 print (ord ("你" ))print (hex (ord ("你" )))
输出结果:
所以我们判断是否为连续字符:
1 if currentCharCode == chr (ord (prevCharCode ) + 1 )
进一步封装为方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 def isSeries (pwd ): if pwd and (len (pwd) > 0 ): ascSeriesCount = 1 descSeriesCount = 1 for i in range (len (pwd)): currentCharCode = pwd[i] if i == 0 : prevCharCode = "" else : prevCharCode = pwd[i - 1 ] if currentCharCode == chr (ord (prevCharCode) + 1 ): ascSeriesCount = ascSeriesCount + 1 if ascSeriesCount == seriesCount: return True else : ascSeriesCount = 1 for i in range (len (pwd) - 1 ): currentCharCode = pwd[i] if (i - 1 ) >= 0 : prevCharCode = pwd[i - 1 ] else : prevCharCode = "" if chr (ord (currentCharCode) + 1 ) == prevCharCode: descSeriesCount = descSeriesCount + 1 if descSeriesCount == seriesCount: return True else : descSeriesCount = 1 return False
重复字符判断 重复字符判断,就需要迭代器遍历和计数器统计了。不过效率有点低:
1 2 3 4 5 6 7 8 9 10 11 12 13 # 判断密码是否包含重复字段 def isRepeate(pwd ): if pwd and (len (pwd ) > 0 ): for i in range (len (pwd )): currentChar = pwd [i] if i == 0 : prevChar = "" else : prevChar = pwd [i - 1 ] if currentChar == prevChar: return True return False
最终效果 在线演示 最终,我用JavaScript也通过本文思路,再现了本文Python实现的过程,大家如果觉得图文不形象,可以亲自体验:
代码解析 上文的正则表达式集中解决判断问题,这边梳理如何生成问题。 首先,我们设置一个方法体:
1 def getPWD (enableNumber, enableLetter, enableSpecial,passwordLength )
其中,考虑到一些网站会对密码格式有所限制,所以这边进行选择处理 :
enableNumber:生成密码是否需要有数字
enableLetter:生成密码是否需要有数字
enableSpecial:生成密码是否需要特殊字符
passwordLength:生成密码长度
为了保证生产各个元素,有出场的机会,我们限定一下最短长度:
1 2 if passwordLength<3 : return "错误!密码长度不得少于3位"
之后,创建字符集:
1 2 3 4 5 6 7 numeric = '0123456789' stringLetter = string.ascii_letterspunctuation = '!@#$%^&*()_+~`|}{[]\:;?><,./-=' password = "" character = ""
配合随机数生成:
1 2 3 4 5 6 7 8 9 10 11 12 13 while len (password) < passwordLength: if enableNumber : entity0 = random .randint(0 , len (numeric ) - 1 ) character = numeric [entity0] + character if enableLetter: entity1 = random .randint(0 , len (string .ascii_letters) - 1 ) character = stringLetter[entity1] + character if enableSpecial: entity2 = random .randint(0 , len (punctuation) - 1 ) character = punctuation[entity2] + character password = password + character character = ""
这里我在写的时候,忽略了长度问题:因为一次生成是那个元素的原因,造成用户如果是选择密码长度非3的倍数,生成的密码会溢出;所以,大家可以根据自己的需求,这边再改改。
因为random实际上是伪随机数,所以我们重新打乱字符并格式化为字符串:
1 2 3 4 5 6 # 生成的密码转换为list password = list(password)# 使用random重新打乱list集合 random.shuffle(password)# 重新拼接为字符串 new Password = "" .join(password)
总结📝 强密码的生成和判断就到这里,揉的比较杂碎。如果需要复刻,可能需要一些时间。 本文着重处理:
强密码判断(主要是正则匹配和逻辑代码的使用)
强密码生成(随机数的使用)
作者:Mintimate
博客:https://www.mintimate.cn
Mintimate’s Blog,只为与你分享