电子邮件地址为UserName BUG

erg*_*ysr 12 sql-server asp.net-mvc

我正在开发一个带有SQL Server数据库的MVC4网站.我想用他们的电子邮件地址注册人.

但是,如果电子邮件地址包含该字符i,则WebSecurity.CreateUserAndAccount方法抛出一个异常说:

身份验证提供程序返回错误.请验证您的输入,然后重试.如果问题仍然存在,请与系统管理员联系.

我研究了很多并找到了一些关于它的帖子,但没有解决方案.

http://forums.asp.net/t/1862233.aspx/1?How+can+i+use+email+address+for+username+in+MVC4+Membership

http://aspnetwebstack.codeplex.com/workitem/714

Ste*_*ger 3

您的根本问题是您尝试输入非 ASCII 字符作为电子邮件地址。

\n\n

“ASCII 字符集”将您限制为美国英语字母表,而这恰好是拉丁字母表。

\n\n

我不会说土耳其语,但正如http://aspnetwebstack.codeplex.com/workitem/714中指出的那样

\n\n

在土耳其语中,\'i\' 是小写字母,而 \'\xc4\xb0\' 是“i”的大写字母。
\n在拉丁字母中,你(和我)碰巧没有 IT 知识,\'i\' 是小写字母,而 \'I\' 是 i 的大写字母。

\n\n

所以你有一个不属于 EN-US ASCII 字符集的字符。
\n因此,排序规则设置会阻止您将非 ASCII 字符输入数据库,从而导致错误。
\n因此,您不应更改排序规则设置(这将允许无效的邮件地址)。

\n\n

正如所指出的,ToUpper(应该是 ToUpperInvariant)是罪魁祸首,因为它在幕后将 \'i\' 更改为 \'\xc4\xb0\',这不是有效的 ASCII 字符。

\n\n

这是字符串/字符的 ToUpper 方法的常见问题。
\n例如,德语字母表中包含字母 \xc3\x9f (Unicode U+00DF),也称为“double s”,它首先没有对应的大写字符,因此如果您尝试使用 toUpper 比较字符串,总是会失败,这就是为什么你应该总是使用 ToLower() 来比较字符串——另一个 Microsoft 失败。

\n\n

ToUpper 也发生了类似的情况。

\n\n

您首先需要做的是确保您的用户输入 ASCII 字符。
\n这是不可能的,因为它们有土耳其语键盘和语言环境,虽然小 i 看起来与 ASCII 小 i 相似,但它具有不同的数字表示形式,因此有不同的大写字符(顺便说一句,小写也是如此)。

\n\n

因此,您需要做的是在调用会员资格方法之前对输入字符串进行“拉丁化/罗马化”。

\n\n

我在使用第三方的仅支持 ASCII 的软件时遇到了类似的问题,该软件在元音变音和法语重音字符上失败,并使用以下方法解决了这个问题。
\n您可能想检查土耳其语 \xc3\xa4\xc3\xb6\xc3\xbc 的数字表示形式是否与(瑞士)德语 \xc3\xa4\xc3\xb6\xc3\xbc 不同。在这里使用。

\n有关风险和副作用,请阅读包装说明书并咨询您的医生或药剂师。

\n\n
    // string str = ApertureSucks.Latinize("(\xc3\xa6\xc3\xb8\xc3\xa5 \xc3\xa2\xc3\xb4\xc3\xbb?a\xc3\xa8");\n    public static string Latinize(string stIn)\n    {\n        // Special treatment for German Umlauts\n        stIn = stIn.Replace("\xc3\xa4", "ae");\n        stIn = stIn.Replace("\xc3\xb6", "oe");\n        stIn = stIn.Replace("\xc3\xbc", "ue");\n\n        stIn = stIn.Replace("\xc3\x84", "Ae");\n        stIn = stIn.Replace("\xc3\x96", "Oe");\n        stIn = stIn.Replace("\xc3\x9c", "Ue");\n        // End special treatment for German Umlauts\n\n        string stFormD = stIn.Normalize(System.Text.NormalizationForm.FormD);\n        System.Text.StringBuilder sb = new System.Text.StringBuilder();\n\n        for (int ich = 0; ich < stFormD.Length; ich++)\n        {\n            System.Globalization.UnicodeCategory uc = System.Globalization.CharUnicodeInfo.GetUnicodeCategory(stFormD[ich]);\n\n            if (uc != System.Globalization.UnicodeCategory.NonSpacingMark)\n            {\n                sb.Append(stFormD[ich]);\n            } // End if (uc != System.Globalization.UnicodeCategory.NonSpacingMark)\n\n        } // Next ich\n\n\n        //return (sb.ToString().Normalize(System.Text.NormalizationForm.FormC));\n        return (sb.ToString().Normalize(System.Text.NormalizationForm.FormKC));\n    } // End Function Latinize\n
Run Code Online (Sandbox Code Playgroud)\n\n

最后但并非最不重要的一点是,我不会使用内置的 ASP.NET 成员资格提供程序,因为它通过用户名 + 应用程序名称到角色名称来连接表,而不是使用唯一的 id。这意味着您将无法在不更改所有映射表的情况下更改用户或组/角色名称。\n我认为这样做是非常不可取的,并且绝对是愚蠢和粗心的,如果不是微软方面的彻底危险的话。
\n我什至会称将此类垃圾释放到野外是无礼的。

\n\n

下面的“东西”证明了这个问题是完全愚蠢的,永远不应该使用

\n\n
CREATE TABLE [dbo].[UsersInRoles](\n    [Username] [varchar](255) NOT NULL,\n    [Rolename] [varchar](255) NOT NULL,\n    [ApplicationName] [varchar](255) NOT NULL,\n CONSTRAINT [usersinroles_pkey] PRIMARY KEY CLUSTERED \n(\n    [Username] ASC,\n    [Rolename] ASC,\n    [ApplicationName] ASC\n)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]\n) ON [PRIMARY]\n
Run Code Online (Sandbox Code Playgroud)\n\n

出于以下原因:

\n\n
    \n
  • 问题 1:字符串连接将使用户加入角色的速度非常慢 - 对性能非常\n不利
  • \n
  • 问题 2:varchar - 应该是 nvarchar,除非\n您生活在纯英语的世界中
  • \n
  • 问题 3:字段长度\n用户名和角色名必须符合最新活动\n目录的最低规格,否则与\n活动目录同步时会出现问题。另外,Active Directory 允许使用 unicode 字符。
  • \n
  • 问题 4:没有对用户和角色表的外键引用 -\n迟早会出现数据垃圾(通常更快)
  • \n
  • 问题 5:如果现在更改用户名或\n组名,则 UserInRoles 将不会更新,并且用户的组\nmap 将成为孤立的 - 最终会产生数据垃圾,左连接将带来空列,程序可能会因以下原因而崩溃:未处理的 NullReferenceException。
  • \n
  • 问题 6:由于缺少外键引用,因此可以更改用户名/组名
  • \n
  • 问题7:数据垃圾迟早会导致报告/显示数据时出现多行
  • \n
  • 问题8:这里使用的主键应该是唯一约束
  • \n
  • 问题 9:有一个组名称,但例如组“管理员”需要本地化为多种语言,而会员资格提供商不支持这一点。另外,组名属于映射表,因为一个组可以有N种语言的N个名称,然后必须确保组名在特定语言内是唯一的。
  • \n
  • 问题10:这里不可见,但用户表包含一个字段电子邮件。这是彻底的失败,因为一个用户可以有 n 个电子邮件地址,聪明的会员提供商应该考虑到这一点,而不是愚蠢地限制用户只有一个电子邮件地址。
  • \n
  • 问题 11:此外,上述电子邮件字段的长度限制为 128 个字符,这小于 RFC 中电子邮件地址允许的最大字符数。失败 - 迟早有人将无法输入他的邮件地址 - 即使他只有一个。有效电子邮件地址的最大长度是多少?
  • \n
\n\n

我确信 MS 提供的会员提供者惨败还存在更多问题。 \n例如,使用快速哈希算法 (MD5),这是这种情况的反模式,因为这允许彩虹表攻击,特别是如果哈希值没有加盐。\n如果 MS 会员提供程序展示了一件事,那么这就是不设计会员提供程序的方法。

\n