Django:电子邮件地址的md5哈希的Base64是否低于30个字符?

时间:2012-06-18 19:21:13

标签: python django

我正在调查几个小时以来在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个字符吗?如果这是真的,怎么能实现呢?

非常感谢,

3 个答案:

答案 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编码空间) )。