6

我需要一个关于做什么的建议。我目前正在使用 WebSecurity 方法来完成所有与帐户相关的工作。但是它不支持电子邮件唯一性验证,所以我有几个选择:

  1. 编写(子类)一个新的 SimpleMembershipProvider 覆盖现有的 createuserAndAccount 方法来验证电子邮件地址。但我还必须实现登录-注销功能(就像 websecurity 一样)和其他一些功能。

  2. 在数据库上添加唯一性约束并在我的代码中捕获它们。但是,这会导致我依赖于数据库。

  3. 这可能有点便宜,但我可以将 WebSecurity 源代码(因为它打开)复制/粘贴到一个新类上,并修改 createUserAndAccount 方法。

还有其他选择吗?我目前的目标是选项 3,这将是最快的方式。附带说明一下,将来我也将需要角色,我不确定 WebSecurity 是否为它们提供支持。

4

2 回答 2

5

如果是我,我可能会采取以下方式:

首先,假设您将 SimpleMembership 与实体框架或某些数据库连接(ADO、LINQ to SQL 等)一起使用,您将拥有两个组件:WebSecurity.*方法调用和用于进行配置文件更改的数据库连接。就我个人而言,我会将其添加CONSTRAINT到数据库中以确保您的数据是纯净的,但您也可以实现一个处理此逻辑的会员服务。

首先,将它们分组到可以在控制器中引用的接口中(如下所示):

public interface IMembershipService
{
    Int32 CurrentUserId { get; }
    String CurrentUserName { get; }
    Boolean IsAuthenticated { get; }

    Boolean CreateUserAndAccount(String username, String password, String emailaddress = null);
    Boolean CreateUserAndAccount(String username, string password, out String confirmationToken, String emailaddress = null);
    Boolean Login(String username, String password, Boolean persistCookie = false);
    void Logout();
}

然后,您可以将服务实现为 SimpleMembership 和数据库连接的混合体。为了保持通用性,我使用了该IRepository<T>模式,但这可能是直接DbContext的 ,ObjectContext等。我也保持简短,所以请原谅缺少校验和和简短的实现。

public class MembershipService : IMembershipService
{
    protected readonly SimpleMembershipProvider membershiProvider;
    protected readonly SimpleRoleProvider roleProvider;
    protected readonly IRepository<UserProfile> profileRepository;

    public MembershipService(IRepository<UserProfile> profileRepository)
    {
        this.membershipProvider = Membership.Provider as SimpleMembershipProvider;
        this.roleProvider = Role.Provider as SimpleRoleProvider;
        this.profileRepository = userRepository;
    }

    #region IMembershipService Implementation

    public Int32 CurrentUserId
    {
        get { return WebSecurity.CurrentUserId; }
    }
    public String CurrentUserName
    {
        get { return WebSecurity.CurrentUserName; }
    }
    public Boolean IsAuthenticated
    {
        get { return WebSecurity.IsAuthenticated; }
    }

    public Boolean CreateUserAndAccount(String username, String password, String emailaddress = null)
    {
        // validate the email address is unique
        if (!this.profileRepository.Any(x => x.EmailAddress == emailaddress))
        {
            WebSecurity.CreateUserAndAccount(username, password, new
            {
                EmailAddress = emailaddress
            }, createConfirmationToken);
            return true;
        }
        else
        {
            // handle the error how you see fit
            // (maybe even exception?)
            return false;
        }
    }
    public Boolean CreateUserAndAccount(String username, String password, out String confirmationToken, String emailaddress = null, out)
    {
        // validate the email address is unique
        if (this.profileRepository.First(x => x.EmailAddress == emailaddress) == null)
        {
            confirmationToken = WebSecurity.CreateUserAndAccount(username, password, new
            {
                EmailAddress = emailaddress
            }, createConfirmationToken);
            return true;
        }
        else
        {
            // handle the error how you see fit
            // (maybe even exception?)
            confirmationToken = String.Empty;
            return false;
        }
    }
    public Boolean Login(String username, String password, Boolean persistCookie = false)
    {
        return WebSecurity.Login(username, password, persistCookie);
    }
    public void Logout()
    {
        WebSecurity.Logout();
    }

    #endregion
}

现在你可以在你的控制器中引用这个接口并将逻辑放在一个地方。如果您使用的是 DI 容器,显然要注册它,但这里有一个示例实现:

public class AccountController: Controller
{
    private readonly IMembershipService membershipService;

    public AccountController(IMembershipService membershipService)
    {
        this.membershipService = membershipService;
    }

    /* ... */

    [HttpPost, ValidateAntiForgeryToken]
    public ActionResult Register(LoginViewModel model, String returnUrl)
    {
        if (ModelState.IsValid)
        {
            if (this.membershipService.CreateUserandAccount(model.Username, model.Password, model.EmailAddress))
            {
                this.membershipService.Login(model.Username, model.Password);
                if (!String.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl))
                {
                    return Redirect(returnUrl);
                }
                return RedirectToRoute("Default");
            }
            else
            {
                ModelState.AddModelError("", "Unable to register.");
            }
        }
        return View(model);
    }

    /* ... */
}

如果您使用的是 EntityFramework,您还可以使用IValidatableObject. 为了避免重复,这是另一个检查唯一条目的 SO 问题/答案:

实体框架 IValidatableObject

于 2013-04-16T13:41:34.487 回答
0

使用选项一 1. 您的自定义成员资格是否继承自 ExtendedMemberShipproviderAccountMembershipProvider : ExtendedMembershipProvider

  1. 使用 WebSecurity 的包装器进行单元可测试性示例

     public interface IWebSecurity
                    {
    
                        bool Login(string userName, string password, bool rememberMe = false);
                        bool ChangePassword(string userName, string currentnPassword, string newPassword);
                        void LogOut();
                    }
    

    公共类 WebSecurityWrapper : IWebSecurity

    {

        public bool Login(string userName, string password, bool rememberMe)
        {
            return WebSecurity.Login(userName, password, rememberMe);
        }
    
    
        public bool ChangePassword(string userName, string currentPassword, string newPassword)
        {
            return WebSecurity.ChangePassword(userName, currentPassword, newPassword);
        }
    
        public void LogOut()
        {
            WebSecurity.Logout();
        }
    }
    

在这里您可以添加您的电子邮件更改任何您想要的方法

  1. 在您的 web.config 中将您的会员提供者注册为默认提供者
于 2013-04-15T22:40:27.640 回答