使用Membership API可以更改用户名吗?

32

我正在使用ASP.NET的默认SQL membership提供程序,并且我想提供一个页面来更改用户的用户名。我相信我可以通过自定义提供程序来实现这一点,但是默认提供程序能否做到呢?

我的第二个问题是: 我是否应该允许用户在创建账户后更改他们的用户名?

7个回答

24

确实,SQL Membership Provider 默认设置不允许更改用户名。但是,如果你在网站上有一个有效的理由允许用户更改他们的用户名,就没有本质的理由阻止它。 SQL 数据库中的所有表都没有用户名作为关键字,一切都基于用户 ID,从实现的角度来看,这将非常容易。


1
尽管数据库表基于单独的UserID键,但.NET Membership提供程序运行的SP是基于用户名的。我没有仔细查看源代码,但这似乎表明如果更改用户的用户名,则后续的成员资格操作可能会失败(尝试使用旧的用户名)。 - Toby
1
Toby的担忧不是问题吗?“也许一些SP可能会失败”似乎是一个非常严重的理由,不接受答案或在验证之前不使用它。有什么想法吗? - dnord
3
如果您的代码在更新后仍将过时的用户名传递给提供程序,那么托比是正确的,显然会出现问题。否则,没有任何负面影响。 - Jonathan Freeland

12
如果您使用SqlMembershipProvider,您可以对其进行扩展-这也与此问题有关。
Roadkill是一个维基引擎,而不是我编码风格的描述。
using System;
using System.Web.Security;
using System.Configuration;
using System.Data.SqlClient;
using System.Data;
using System.Web.Configuration;

namespace Roadkill.Core
{
    public class RoadkillMembershipProvider : SqlMembershipProvider
    {
        private string _connectionString;

        protected string ConnectionString
        {
            get
            {
                if (string.IsNullOrWhiteSpace(_connectionString))
                {
                    Configuration config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
                    MembershipSection section = config.SectionGroups["system.web"].Sections["membership"] as MembershipSection;
                    string defaultProvider = section.DefaultProvider;
                    string connstringName = section.Providers[defaultProvider].ElementInformation.Properties["connectionStringName"].Value.ToString();
                    _connectionString = config.ConnectionStrings.ConnectionStrings[connstringName].ConnectionString;
                }

                return _connectionString;
            }
        }

        public bool ChangeUsername(string oldUsername, string newUsername)
        {
            if (string.IsNullOrWhiteSpace(oldUsername))
                throw new ArgumentNullException("oldUsername cannot be null or empty");

            if (string.IsNullOrWhiteSpace(newUsername))
                throw new ArgumentNullException("newUsername cannot be null or empty");

            if (oldUsername == newUsername)
                return true;

            using (SqlConnection connection = new SqlConnection(ConnectionString))
            {
                connection.Open();

                using (SqlCommand command = connection.CreateCommand())
                {
                    command.CommandText = "UPDATE aspnet_Users SET UserName=@NewUsername,LoweredUserName=@LoweredNewUsername WHERE UserName=@OldUsername";

                    SqlParameter parameter = new SqlParameter("@OldUsername", SqlDbType.VarChar);
                    parameter.Value = oldUsername;
                    command.Parameters.Add(parameter);

                    parameter = new SqlParameter("@NewUsername", SqlDbType.VarChar);
                    parameter.Value = newUsername;
                    command.Parameters.Add(parameter);

                    parameter = new SqlParameter("@LoweredNewUsername", SqlDbType.VarChar);
                    parameter.Value = newUsername.ToLower();
                    command.Parameters.Add(parameter);

                    return command.ExecuteNonQuery() > 0;
                }
            }
        }
    }
}

@russau 是的,我把它放在了域对象的数据注释中。不过任何一个地方都可以。 - Chris S
你怎么称呼那个方法?我猜会员API就是它,所以我的意思是这个方法可以放在一个没有继承SqlMembershipProvider的类中,这样可能更好。 - Carl R
@Carl,你需要将默认提供程序转换为RoadkillMembershipProvider,并首先检查它是否属于该类型。 - Chris S

4

Scott Mitchell在这篇文章中详细介绍了如何处理这种情况:https://web.archive.org/web/20210927191559/http://www.4guysfromrolla.com/articles/070109-1.aspx

他的文章中有一个重要的引用:

不幸的是,理想主义和实用主义很少交汇。在某些情况下——比如允许用户更改用户名时——我们别无选择,只能直接与底层数据存储进行交互。

他还展示了如何在更改用户名或电子邮件后重新验证用户身份。


2
如果您想使用Membership API实现更改用户名,正确的方法似乎是这样的: http://omaralzabir.com/how_to_change_user_name_in_asp_net_2_0_membership_provider/ 基本上,您需要执行以下操作(为了完整起见,我从上面的链接中复制了以下内容):
1. 使用新的电子邮件地址创建新用户 2. 获取旧帐户的密码并将其设置为新帐户。如果无法通过Membership提供程序获取旧密码,则要求用户提供密码。 3. 为新用户帐户创建新配置文件 4. 将所有属性从旧配置文件复制到新配置文件对象中。 5. 注销旧帐户的用户 6. 自动登录到新账户,以便用户不会注意到刚刚发生了什么。

7
虽然我不建议这种做法:如果您将其他内容与用户ID绑定,那么在系统发展并且新的事物依赖于UserID时,您可能会冒失地丢失用户的内容。请注意保护用户数据。 - Arve Systad

0

这里有一个版本,它包含了企业库DAB和其他一些小改动。此外,我认为没有必要返回布尔值,因为它要么成功执行,要么抛出异常。

        public static void ChangeUsername(string oldUsername, string newUsername)
    {
        if (string.IsNullOrWhiteSpace(oldUsername))
        {
            throw new ArgumentNullException("oldUsername cannot be null or empty");
        }

        if (string.IsNullOrWhiteSpace(newUsername))
        {
            throw new ArgumentNullException("newUsername cannot be null or empty");
        }

        if (oldUsername.Equals(newUsername))
        {
            return;
        }

        Database db = DatabaseFactory.CreateDatabase();
        using (DbCommand cmd = db.GetSqlStringCommand("UPDATE dbo.aspnet_Users SET UserName=@NewUsername, LoweredUserName=@LoweredNewUsername WHERE UserName=@OldUsername"))
        {
            db.AddInParameter(cmd, "@OldUsername", DbType.String, oldUsername);
            db.AddInParameter(cmd, "@NewUsername", DbType.String, newUsername);
            db.AddInParameter(cmd, "@LoweredNewUsername", DbType.String, newUsername.ToLower());

            db.ExecuteNonQuery(cmd);                
        }
    }

0

由于Membership API不允许直接修改用户名,因此您可以直接访问数据库中的aspnet_Membership表。


我强烈反对这种方法。如果您直接在AspNetUsers表上更改用户名,该用户将无法再登录。 - Kabindas

-3

MembershipUser类不允许修改Username属性,因此您无法这样做。

实际上,您不应该允许更改用户名。如果您以某种方式允许更改,则会失去其目的和性质。


我最终编写了自己的提供程序,然后我添加了这个功能。 - Bobby Ortiz
9
它完全不会失去它的目的或本质。假设您为一个帐户创建了这个__curious__feek@gmail.com。哎呀,您拼错了geek!现在你完全搞糊涂了。客户总是会这样做。如果您正在使用电子邮件作为登录名,那么您就会有问题。 - Simon_Weaver
为什么不允许用户更改用户名?正如上面的评论所说,它并没有被用于在会员存储中唯一地识别用户。如果您的客户在名称中打错了一个字母并想要更改,那该怎么办? - Stephanvs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接