我正在调查几个小时以来在Django身份验证中使用电子邮件地址而不是用户名的最佳方法。本主题已多次讨论过,但给定的结果不一致。
1)答案here指向snippet,只需在其中加上“@”字符即可区分用户名和电子邮件。电子邮件和用户名的最大长度不相同,但在答案中未予考虑。
2)第二个答案 - 来自同一个link - 来自S.Lott(13票)正在用admin.site做一些黑魔法。对我来说,代码正在做什么是没有意义的,这是接受的做法简短而甜蜜的方式吗?
3)然后我找到了this solution,这看起来几乎是完美的(对我来说很有意义):
username = uuid.uuid4().hex[:30]
它只选择一个唯一的Python生成ID作为用户名的前30个字符。但仍有可能发生碰撞。然后我遇到了一个有人声称的帖子
md5哈希的base64编码有25个字符
如果这是真的,我们不能采用电子邮件地址的md5哈希的base64编码,并保证100%唯一的用户名,这些用户名也不到30个字符吗?如果这是真的,怎么能实现呢?
非常感谢,
答案 0 :(得分:4)
你可以这样做:
>>> from hashlib import md5
>>> h = md5('email@example.com').digest().encode('base64')[:-1]
>>> _
'Vlj/zO5/Dr/aKyJiOLHrbg=='
>>> len(h)
24
您可以忽略最后一个字符,因为它只是一个新行。碰撞的可能性与MD5哈希相同,在base64中编码时不会丢失信息。
>>> original = md5('email@example.com').digest()
>>> encoded = original.encode('base64')
>>> original == encoded.decode('base64')
True
答案 1 :(得分:2)
MD5 hashes总是16个字节长,Base64将3个字节的组编码为4个字符;因此(16/3向上舍入)=>对于编码为Base64的MD5哈希,6组3个,4个= 24个字符。
但是,请注意上面链接的维基百科页面说明:
然而,已经证明MD5不具有抗冲击性。
因此,您无法指望此方法为您提供来自电子邮件地址的唯一用户名。在hashlib
module:
>>> from hashlib import md5
>>> md5('foo@bar.com').digest().encode('base64').strip()
'862kBc6JC2+CBAlN6xLYqA=='
答案 2 :(得分:2)
UUID
是128位,因此您可以直接在其上应用base64以获取22个字符长的字符串(通过删除固定填充'=='
,正如Gumbo在问题的评论中所建议的那样)
>>> import base64
>>> len(base64.urlsafe_b64encode(uuid.uuid4().bytes).rstrip('='))
22
此处,urlsafe_b64encode
和'='
的剥离用于避免User.username
字段不喜欢的字符,包括'/' '+'
和'='
此外,UUID有两位固定'10'
(因此十六进制表示中的第17个字符始终为8,9,A,B
)和四位版本,请检查the wiki。
因此,您可以沿着w / 2有效位丢弃4 + 2 = 6位,以获得30个字符长的十六进制字符串:
>>> s = uuid.uuid4().hex
>>> len(s[:12] + s[13:16] + s[17:])
30
通过这种方式,只需将s[:30]
切换为s,就可以丢弃2个有效位而不是8个,并且可以期待更好的唯一性(最多为1/4的uuid编码空间) )。