在MVC3中我要*覆盖多少MembershipProvider

时间:2012-01-27 15:33:18

标签: asp.net asp.net-mvc asp.net-mvc-3

到目前为止,我已经在我的MVC3应用程序中完成了所有身份验证工作,即通过我的MemberRepository课程验证成员并创建成员。我现在想通过自定义MembershipProvider去官方。到目前为止,我只收集到了我真的需要覆盖这个类的ValidateUser方法,因为我没有使用Login控件,所以我甚至不确定我是否必须这样做。

覆盖GetUserCreateUser等方法会为我的聚会带来未经邀请的类型,例如MembershipUser,我有一个精心设计的Member课程。如果我不打算使用任何内置控件或管理工具,如果我不打算使用任何内置控件或管理工具,那么有人可以为我清理我是否真的需要自定义成员资格提供程序,如果我这样做,我是否应该将我的覆盖限制在绝对必要的范围内,这是什么?

3 个答案:

答案 0 :(得分:2)

这是我为单元测试编写的。这是最小的可能。

public class MockMembershipProvider : MembershipProvider
{
    public IList<MembershipUser> Users { get; private set; }

    private string _applicationName;
    public override string ApplicationName
    {
        get
        {
            return _applicationName;
        }
        set
        {
            _applicationName = value;
        }
    }

    public override bool ChangePassword(string username, string oldPassword, string newPassword)
    {
        throw new NotImplementedException();
    }

    public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
    {
        throw new NotImplementedException();
    }

    public override MembershipUser CreateUser(
        string username, 
        string password, 
        string email, 
        string passwordQuestion, 
        string passwordAnswer, 
        bool isApproved, 
        object providerUserKey, 
        out MembershipCreateStatus status)
    {
        var user = new MembershipUser(ProviderName, username, username, email, passwordQuestion, null, isApproved, false, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now);
        Users.Add(user);
        status = MembershipCreateStatus.Success;
        return user;
    }

    public override bool DeleteUser(string username, bool deleteAllRelatedData)
    {
        var u = Users.Where(mu => mu.UserName.Equals(username, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
        if (u == null) return false;
        Users.Remove(u);
        return true;
    }

    public override bool EnablePasswordReset
    {
        get { return false; }
    }

    public override bool EnablePasswordRetrieval
    {
        get { return false; }
    }

    public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
    {
        throw new NotImplementedException();
    }

    public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
    {
        var users = (from u in Users
                     where u.UserName.Equals(usernameToMatch, StringComparison.OrdinalIgnoreCase)
                     select u).ToList();
        totalRecords = users.Count;
        return ToMembershipUserCollection(users);
    }

    public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
    {
        var list = Users.Skip(pageIndex * pageSize).Take(pageSize);
        totalRecords = list.Count();
        var result = new MembershipUserCollection();
        foreach (var u in list)
        {
            result.Add(u);
        }
        return result;
    }

    public override int GetNumberOfUsersOnline()
    {
        return Users.Count();
    }

    public override string GetPassword(string username, string answer)
    {
        throw new NotImplementedException();
    }

    public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
    {
        return (from u in Users
                where u.ProviderUserKey.ToString() == providerUserKey.ToString()
                select u).FirstOrDefault();
    }

    public override MembershipUser GetUser(string username, bool userIsOnline)
    {
        return (from u in Users
                where u.UserName.Equals(username, StringComparison.OrdinalIgnoreCase)
                select u).FirstOrDefault();
    }

    public override string GetUserNameByEmail(string email)
    {
        return (from u in Users
                where u.Email.Equals(email, StringComparison.OrdinalIgnoreCase)
                select u.UserName).FirstOrDefault();
    }

    public override int MaxInvalidPasswordAttempts
    {
        get { return 3; }
    }

    public override int MinRequiredNonAlphanumericCharacters
    {
        get { return 1; }
    }

    public override int MinRequiredPasswordLength
    {
        get { return 6; }
    }

    public override int PasswordAttemptWindow
    {
        get { return 10; }
    }

    public override MembershipPasswordFormat PasswordFormat
    {
        get { throw new NotImplementedException(); }
    }

    public override string PasswordStrengthRegularExpression
    {
        get { return null; }
    }

    public override string Name
    {
        get
        {
            return ProviderName;
        }
    }

    public string ProviderName { get; set; }

    public override string ResetPassword(string username, string answer)
    {
        throw new NotImplementedException();
    }

    public override bool RequiresQuestionAndAnswer
    {
        get { return false; }
    }

    public override bool RequiresUniqueEmail
    {
        get { return true; }
    }

    private MembershipUserCollection ToMembershipUserCollection(IEnumerable<MembershipUser> users)
    {
        var result = new MembershipUserCollection();
        foreach (var u in users)
        {
            result.Add(u);
        }
        return result;
    }

    public override bool UnlockUser(string userName)
    {
        return true;
    }

    public override void UpdateUser(MembershipUser user)
    {
        var oldUser = Users.Where(u => u.UserName.Equals(user.UserName, StringComparison.OrdinalIgnoreCase)).Single();
        var index = Users.IndexOf(oldUser);
        Users[index] = user;
    }

    public override bool ValidateUser(string username, string password)
    {
        throw new NotImplementedException();
    }

    public MockMembershipProvider()
    {
        this.ProviderName = "MockMembershipProvider";
        Users = new List<MembershipUser>();
    }
}

public class FakeMembershipProvider : MockMembershipProvider
{
    public FakeMembershipProvider(string name)
    {
        this.ProviderName = name ?? "MockMembershipProvider";
    }
    public override MembershipUser CreateUser(
        string username,
        string password,
        string email,
        string passwordQuestion,
        string passwordAnswer,
        bool isApproved,
        object providerUserKey,
        out MembershipCreateStatus status)
    {
        status = MembershipCreateStatus.ProviderError;
        var user = new MockMembershipUser(); 
        user.Password = password;
        user.User = username;
        user.UserKey = providerUserKey;
        Users.Add(user);
        status = MembershipCreateStatus.Success;
        return user;
    }
}

public class MockMembershipUser : MembershipUser
{
    public string Password { get; set; }
    public string User { get; set; }
    public object UserKey { get; set; }

    public override string UserName { get { return User; } }

    public override string Comment { get; set; }

    public override object ProviderUserKey { get { return UserKey; } }

    public override string GetPassword()
    {
        return Password ?? string.Empty;
    }

答案 1 :(得分:1)

您想要将您的网络应用与MembershipRepository分开吗?

如果是这样,请在custom MembershipProvider中实现所有相同的功能,以便您的应用仅依赖于.NET Membership classes(除了您的web.config)。

如果没有,那就不要打扰了。

答案 2 :(得分:1)

自定义MembershipProvider

如果您正在使用MembershipProvider,则可以“免费”获得一些不错的安全功能:例如,您可以设置web.config以将每个未经身份验证的用户重定向到登录页面。或者,您可以将站点的特定部分设置为仅对具有特定角色的用户可见。如果这些功能对您的项目没有意义,或者您已经以其他方式实现了它们的等效功能,则实现自定义MembershipProvider并没有多大意义。

<强>的SqlMembershipProvider

您可能要考虑的另一种可能性是切换您自己的实现以使用SqlMembershipProvider来处理成员函数。

SqlMembershipProvider为常见任务提供了一个强大的,经过验证的平台,这些任务对于每个项目都需要重新创建:帐户创建,验证,删除,锁定,密码重置,基本角色等。如果您已经完成所有操作你自己没有使用SqlMembershipProvider,实际上没有任何一点只是为了拥有它而创建一个。但是,你应该小心,因为你很可能在自己的实现中做错了。例如,

  • 您是将密码存储为纯文本还是存储为哈希?
  • 您是否接受Rainbow Table攻击,或者您正在腌制哈希?
  • 您是否在连续尝试了50次以上无效密码尝试后锁定了人们的帐户,或者您是否让黑客继续捣乱直到他们强行进入某人的帐户?

SqlMembershipProvider已经以易于配置的方式解决了所有这些问题。您可能希望拥有自己的成员资格接口,并且DTO只需将此默认MembershipProvider包装起来,这样您就不必担心这些不同的问题。这样,您的大多数代码都不必与这些“未经邀请的类型”进行交互,但您仍然可以在后端获得广泛使用且经过验证的安全框架的优势。