12

我正在开发一个带有 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

4

2 回答 2

3

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

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

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

在土耳其语中,“i”是小写,而“İ”是“i”的大写。
在您(和我)碰巧没有 IT 方面的拉丁字母表中,“i”是小写字母,而“I”是 i 的大写字母。

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

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

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

ToUpper 也发生了类似的事情。

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

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

我在使用第三方提供的仅支持 ASCII 的软件时遇到了类似的问题,该软件在变音符号和法语重音字符上失败,并使用以下方法解决了这个问题。
您可能想检查土耳其 äöü 是否与我在这里使用的(瑞士)德语 äöü 没有不同的数字表示。

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

    // string str = ApertureSucks.Latinize("(æøå âôû?aè");
    public static string Latinize(string stIn)
    {
        // Special treatment for German Umlauts
        stIn = stIn.Replace("ä", "ae");
        stIn = stIn.Replace("ö", "oe");
        stIn = stIn.Replace("ü", "ue");

        stIn = stIn.Replace("Ä", "Ae");
        stIn = stIn.Replace("Ö", "Oe");
        stIn = stIn.Replace("Ü", "Ue");
        // End special treatment for German Umlauts

        string stFormD = stIn.Normalize(System.Text.NormalizationForm.FormD);
        System.Text.StringBuilder sb = new System.Text.StringBuilder();

        for (int ich = 0; ich < stFormD.Length; ich++)
        {
            System.Globalization.UnicodeCategory uc = System.Globalization.CharUnicodeInfo.GetUnicodeCategory(stFormD[ich]);

            if (uc != System.Globalization.UnicodeCategory.NonSpacingMark)
            {
                sb.Append(stFormD[ich]);
            } // End if (uc != System.Globalization.UnicodeCategory.NonSpacingMark)

        } // Next ich


        //return (sb.ToString().Normalize(System.Text.NormalizationForm.FormC));
        return (sb.ToString().Normalize(System.Text.NormalizationForm.FormKC));
    } // End Function Latinize

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

下面的“东西”展示了这个问题的完全愚蠢,不应该被使用

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

原因如下:

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

而且我确信 MS 提供的会员服务提供商的惨败还有很多问题。例如,使用快速散列算法 (MD5),这是这种情况下的反模式,因为它允许彩虹表攻击,尤其是在散列未加盐的情况下。如果 MS 会员提供者展示了一件事,那么这就是不设计会员提供者的方式。

于 2013-02-03T20:05:33.007 回答
0

是的,解决方案是在创建用户和帐户时使用ToUpperInvariant() WebSecurity.CreateUserAndAccount( model.UserName.ToUpperInvariant()); . 这将解决问题。值将以大写字母 (IIIIII@GMAIL.COM) 存储到表中。

于 2014-03-18T09:51:25.993 回答