Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asp mvc 4 Membership and WebSecurity

I need a suggestion about what to do. I'm currently using WebSecurity methods to do all the account related job. However it does not support E-mail uniqueness verification so I have a few options:

  1. Write (subclass) a new SimpleMembershipProvider overwriting the existing createuserAndAccount method to verify the email address. But i would also have to implement the login-logout features (just as websecurity does) and a few others.

  2. Add uniqueness constraints on the database and catch them on my code. However this would cause me to be DataBase dependent.

  3. This might be a little bit cheap, but i could copy/paste the WebSecurity source code (since its open) on a new class, and modify the createUserAndAccount method.

Any other option? I'm aiming for the option 3 at the moment, would be the fastest way. On a side note, on the future I will be requiring roles as well and I'm not sure if WebSecurity provides support for them.

like image 992
Cristiano Coelho Avatar asked Apr 15 '13 16:04

Cristiano Coelho


People also ask

What is Websecurity in MVC?

Based on these templates, the web project is scaffolded and we get the final project structure to work on. If we select an internet application then from the default scaffolding we get a Controller for "Home" and "Account" created. ASP.NET MVC by default provides the authentication using the Web Security.

What is membership in ASP.NET MVC?

Authorization: It is the process of checking that the user is applicable for the process or not. Membership providers in ASP.NET MVC. Roles based authentication for user in ASP.NET MVC.

How can I use ASP net membership provider?

The ASP.NET membership provider is a feature that enables ASP.NET developers to create Web sites that allow users to create unique user name and password combinations. With this facility, any user can establish an account with the site, and sign in for exclusive access to the site and its services.

How can I use ASP Net Membership in C#?

To create a user in our application by using ASP.NET Membership we need the following steps to complete this process. Step 1: Firstly, open visual studio, then go to File Menu and click New -> Web Site. Step 2: After open the new empty website and add a new item Login. aspx in Registration inside Solution Explorer.


1 Answers

If it were me, I'd probably go about it the following way:

First, assuming you're using SimpleMembership with Entity Framework or some database connection (ADO, LINQ to SQL, etc.) you're going to have two components: WebSecurity.* method calls, and the database connection to make profile changes. Personally, I'd add the CONSTRAINT to the database to ensure your data is pure, but you can also implement a membership service that handles this logic, too.

First, group these in to an interface that can be referenced in your controller (something like the following):

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();
}

Then you can implement the service as a hybrid of SimpleMembership and your database connection. For the sake of keeping it generic, I use the IRepository<T> pattern, but this could be a direct DbContext, ObjectContext, etc. I'm also keeping it brief, so excuse the missing checksums and short implementation.

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
}

Now you can reference this interface in your controller and have the logic in one place. if you're using a DI container, obviously register it, but here's an example implementation:

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);
    }

    /* ... */
}

If you're using EntityFramework, you can also use the IValidatableObject. To resist duplicating, here's another SO question/answer that checks for a unique entry:

Entity Framework IValidatableObject

like image 190
Brad Christie Avatar answered Sep 18 '22 16:09

Brad Christie