Home > DeveloperSection > Beginner > Working with SimpleMembership in ASP.NET MVC

Working with SimpleMembership in ASP.NET MVC


ASP.NET MVC ASP.Net  Mvc4  Authentication  Authorization 
Ratings:
0 Comment(s)
 3270  View(s)
Rate this:

Working with SimpleMembership in ASP.NET MVC

Hi everyone in this article I’m explaining about simplemembership, role, websecurity etc.

Description:

This article describes how to use SimpleMembership of WebMatrix.Authenication and authorization that is a very necessary part of web applications. SimpleMembership, introduced with WebMatrix, tries to address these issues by offering a flexible model for authenticating users.

Authentication and authorization are commonly needed features in any modern web application. ASP.NET 2.0 introduced membership and role management through the provider model. Although the default membership and role providers work well in many situations, they are quite rigid in terms of database schema and the way they store user information in the database. For example, while using the default membership provider you don't have much control on the table in which user names (login names) are stored. This rigidity creates difficulties in situations where user login information needs to be stored in a table with custom schema or in situations where authentication is happening via some third party (OAuth based authentication for example).

It relies on the core membership and roles provider of ASP.NET but wraps them in an easy to use and flexible way. Have a look at the following figure that shows the inheritance hierarchy of SimpleMembership.

WebMatrix.WebData assembly contains two important classes, viz. SimpleMembershipProvider and SimpleRoleProvider. The SimpleMembershipProvider class inherits from the ExtendedMembershipProvider class that in turn inherits from the MembershipProvider class residing in the System.Web.Security namespace. The SimpleRoleProvider class inherits directly from the RoleProvider class from the System.Web.Security namespace.

 

Start:

Open visual studio >> File >> New Project >> Select ASP.NET MVC Web Application

Give application name and click ok

After click ok window open like this and select empty template

Install some packages like this

1.      Install entity frame work from Manage NuGet Package

And then install entityframe work

 

2.      Install DotNetOpenAuth package from Manage NuGet Package

 

 

3.      Install Microsoft.AspNet.Web.Optimization

 

 

4.      Install Microsoft.AspNet.WebPages.Data

 

5.      Install Microsoft.AspNet.WebPages.OAuth

 

6.      Download these scripts for validation and use bootstrap menu

 

7.      Download latest bootstrap package for good look and feel

In this sample we use local database for manage login and register

You can use this connection string in web.config

<connectionStrings>

    <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=aspnet-LoginAuthnticationSample-20150122181727;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnet-LoginAuthnticationSample-20150122181727.mdf" providerName="System.Data.SqlClient" />

  </connectionStrings>

 

Now we can add 2 new class inside “App_Start” folder:

1.      AuthConfig.cs

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Microsoft.Web.WebPages.OAuth;

using LoginAuthnticationSample.Models;

 

namespace LoginAuthnticationSample

{

    public static class AuthConfig

    {

        public static void RegisterAuth()

        {

           

        }

    }

}

 

2.      BundleConfig.cs

 

using System.Web;

using System.Web.Optimization;

 

namespace LoginAuthnticationSample

{

    public class BundleConfig

    {

        // For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725

        public static void RegisterBundles(BundleCollection bundles)

        {

            bundles.Add(new ScriptBundle("~/bundles/jquery").Include(

                        "~/Scripts/jquery-{version}.js"));

 

            bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(

                        "~/Scripts/jquery-ui-{version}.js"));

 

            bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(

                        "~/Scripts/jquery.unobtrusive*",

                        "~/Scripts/jquery.validate*"));

 

            // Use the development version of Modernizr to develop with and learn from. Then, when you're

            // ready for production, use the build tool at http://modernizr.com to pick only the tests you need.

            bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(

                        "~/Scripts/modernizr-*"));

 

            bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));

 

            bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(

                        "~/Content/themes/base/jquery.ui.core.css",

                        "~/Content/themes/base/jquery.ui.resizable.css",

                        "~/Content/themes/base/jquery.ui.selectable.css",

                        "~/Content/themes/base/jquery.ui.accordion.css",

                        "~/Content/themes/base/jquery.ui.autocomplete.css",

                        "~/Content/themes/base/jquery.ui.button.css",

                        "~/Content/themes/base/jquery.ui.dialog.css",

                        "~/Content/themes/base/jquery.ui.slider.css",

                        "~/Content/themes/base/jquery.ui.tabs.css",

                        "~/Content/themes/base/jquery.ui.datepicker.css",

                        "~/Content/themes/base/jquery.ui.progressbar.css",

                        "~/Content/themes/base/jquery.ui.theme.css"));

        }

    }

}

 

Now we can add HomeController:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

 

namespace LoginAuthnticationSample.Controllers

{

    public class HomeController : Controller

    {

        public ActionResult Index()

        {

            return View();

        }

    }

}

 

Now we can add AccountModels:

 

using System;

using System.Collections.Generic;

using System.ComponentModel.DataAnnotations;

using System.ComponentModel.DataAnnotations.Schema;

using System.Data.Entity;

using System.Globalization;

using System.Web.Security;

 

namespace LoginAuthnticationSample.Models

{

    public class UsersContext : DbContext

    {

        public UsersContext()

            : base("DefaultConnection")

        {

        }

 

        public DbSet<UserProfile> UserProfiles { get; set; }

    }

 

    [Table("UserProfile")]

    public class UserProfile

    {

        [Key]

        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]

        public int UserId { get; set; }

        public string UserName { get; set; }

    }

 

    public class LocalPasswordModel

    {

        [Required]

        [DataType(DataType.Password)]

        [Display(Name = "Current password")]

        public string OldPassword { get; set; }

 

        [Required]

        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]

        [DataType(DataType.Password)]

        [Display(Name = "New password")]

        public string NewPassword { get; set; }

 

        [DataType(DataType.Password)]

        [Display(Name = "Confirm new password")]

        [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]

        public string ConfirmPassword { get; set; }

    }

 

    public class LoginModel

    {

        [Required]

        [Display(Name = "User name")]

        public string UserName { get; set; }

 

        [Required]

        [DataType(DataType.Password)]

        [Display(Name = "Password")]

        public string Password { get; set; }

 

        [Display(Name = "Remember me?")]

        public bool RememberMe { get; set; }

    }

 

    public class RegisterModel

    {

        [Required]

        [Display(Name = "User name")]

        public string UserName { get; set; }

 

        [Required]

        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]

        [DataType(DataType.Password)]

        [Display(Name = "Password")]

        public string Password { get; set; }

 

        [DataType(DataType.Password)]

        [Display(Name = "Confirm password")]

        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]

        public string ConfirmPassword { get; set; }

    }

 

}

 

Now we can add AccountController:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Transactions;

using System.Web;

using System.Web.Mvc;

using System.Web.Security;

using DotNetOpenAuth.AspNet;

using Microsoft.Web.WebPages.OAuth;

using WebMatrix.WebData;

using LoginAuthnticationSample.Filters;

using LoginAuthnticationSample.Models;

 

namespace LoginAuthnticationSample.Controllers

{

    [Authorize]

    [InitializeSimpleMembership]

    public class AccountController : Controller

    {

        //

        // GET: /Account/Login

 

        [AllowAnonymous]

        public ActionResult Login(string returnUrl)

        {

            ViewBag.ReturnUrl = returnUrl;

            return View();

        }

 

        //

        // POST: /Account/Login

 

        [HttpPost]

        [AllowAnonymous]

        [ValidateAntiForgeryToken]

        public ActionResult Login(LoginModel model, string returnUrl)

        {

            if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))

            {

                return RedirectToLocal(returnUrl);

            }

 

            // If we got this far, something failed, redisplay form

            ModelState.AddModelError("", "The user name or password provided is incorrect.");

            return View(model);

        }

 

        //

        // POST: /Account/LogOff

 

        [HttpPost]

        [ValidateAntiForgeryToken]

        public ActionResult LogOff()

        {

            WebSecurity.Logout();

 

            return RedirectToAction("Index", "Home");

        }

 

        //

        // GET: /Account/Register

 

        [AllowAnonymous]

        public ActionResult Register()

        {

            return View();

        }

 

        //

        // POST: /Account/Register

 

        [HttpPost]

        [AllowAnonymous]

        [ValidateAntiForgeryToken]

        public ActionResult Register(RegisterModel model)

        {

            if (ModelState.IsValid)

            {

                // Attempt to register the user

                try

                {

                    WebSecurity.CreateUserAndAccount(model.UserName, model.Password);

                    WebSecurity.Login(model.UserName, model.Password);

                    return RedirectToAction("Index", "Home");

                }

                catch (MembershipCreateUserException e)

                {

                    ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));

                }

            }

 

            // If we got this far, something failed, redisplay form

            return View(model);

        }

 

        //

        // POST: /Account/Disassociate

 

        [HttpPost]

        [ValidateAntiForgeryToken]

        public ActionResult Disassociate(string provider, string providerUserId)

        {

            string ownerAccount = OAuthWebSecurity.GetUserName(provider, providerUserId);

            ManageMessageId? message = null;

 

            // Only disassociate the account if the currently logged in user is the owner

            if (ownerAccount == User.Identity.Name)

            {

                // Use a transaction to prevent the user from deleting their last login credential

                using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.Serializable }))

                {

                    bool hasLocalAccount = OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));

                    if (hasLocalAccount || OAuthWebSecurity.GetAccountsFromUserName(User.Identity.Name).Count > 1)

                    {

                        OAuthWebSecurity.DeleteAccount(provider, providerUserId);

                        scope.Complete();

                        message = ManageMessageId.RemoveLoginSuccess;

                    }

                }

            }

 

            return RedirectToAction("Manage", new { Message = message });

        }

 

        //

        // GET: /Account/Manage

 

        public ActionResult Manage(ManageMessageId? message)

        {

            ViewBag.StatusMessage =

                message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."

                : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."

                : message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."

                : "";

            ViewBag.HasLocalPassword = OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));

            ViewBag.ReturnUrl = Url.Action("Manage");

            return View();

        }

 

        //

        // POST: /Account/Manage

 

        [HttpPost]

        [ValidateAntiForgeryToken]

        public ActionResult Manage(LocalPasswordModel model)

        {

            bool hasLocalAccount = OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));

            ViewBag.HasLocalPassword = hasLocalAccount;

            ViewBag.ReturnUrl = Url.Action("Manage");

            if (hasLocalAccount)

            {

                if (ModelState.IsValid)

                {

                    // ChangePassword will throw an exception rather than return false in certain failure scenarios.

                    bool changePasswordSucceeded;

                    try

                    {

                        changePasswordSucceeded = WebSecurity.ChangePassword(User.Identity.Name, model.OldPassword, model.NewPassword);

                    }

                    catch (Exception)

                    {

                        changePasswordSucceeded = false;

                    }

 

                    if (changePasswordSucceeded)

                    {

                        return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess });

                    }

                    else

                    {

                        ModelState.AddModelError("", "The current password is incorrect or the new password is invalid.");

                    }

                }

            }

            else

            {

                // User does not have a local password so remove any validation errors caused by a missing

                // OldPassword field

                ModelState state = ModelState["OldPassword"];

                if (state != null)

                {

                    state.Errors.Clear();

                }

 

                if (ModelState.IsValid)

                {

                    try

                    {

                        WebSecurity.CreateAccount(User.Identity.Name, model.NewPassword);

                        return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess });

                    }

                    catch (Exception e)

                    {

                        ModelState.AddModelError("", e);

                    }

                }

            }

 

            // If we got this far, something failed, redisplay form

            return View(model);

        }

 

        #region Helpers

        private ActionResult RedirectToLocal(string returnUrl)

        {

            if (Url.IsLocalUrl(returnUrl))

            {

                return Redirect(returnUrl);

            }

            else

            {

                return RedirectToAction("Index", "Home");

            }

        }

 

        public enum ManageMessageId

        {

            ChangePasswordSuccess,

            SetPasswordSuccess,

            RemoveLoginSuccess,

        }

 

        private static string ErrorCodeToString(MembershipCreateStatus createStatus)

        {

            // See http://go.microsoft.com/fwlink/?LinkID=177550 for

            // a full list of status codes.

            switch (createStatus)

            {

                case MembershipCreateStatus.DuplicateUserName:

                    return "User name already exists. Please enter a different user name.";

 

                case MembershipCreateStatus.DuplicateEmail:

                    return "A user name for that e-mail address already exists. Please enter a different e-mail address.";

 

                case MembershipCreateStatus.InvalidPassword:

                    return "The password provided is invalid. Please enter a valid password value.";

 

                case MembershipCreateStatus.InvalidEmail:

                    return "The e-mail address provided is invalid. Please check the value and try again.";

 

                case MembershipCreateStatus.InvalidAnswer:

                    return "The password retrieval answer provided is invalid. Please check the value and try again.";

 

                case MembershipCreateStatus.InvalidQuestion:

                    return "The password retrieval question provided is invalid. Please check the value and try again.";

 

                case MembershipCreateStatus.InvalidUserName:

                    return "The user name provided is invalid. Please check the value and try again.";

 

                case MembershipCreateStatus.ProviderError:

                    return "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

 

                case MembershipCreateStatus.UserRejected:

                    return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

 

                default:

                    return "An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

            }

        }

        #endregion

    }

}

 

Now we can add new Folder “Filter”

Make new class “InitializeSimpleMembershipAttribute.cs

using System;

using System.Data.Entity;

using System.Data.Entity.Infrastructure;

using System.Threading;

using System.Web.Mvc;

using WebMatrix.WebData;

using LoginAuthnticationSample.Models;

 

namespace LoginAuthnticationSample.Filters

{

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]

    public sealed class InitializeSimpleMembershipAttribute : ActionFilterAttribute

    {

        private static SimpleMembershipInitializer _initializer;

        private static object _initializerLock = new object();

        private static bool _isInitialized;

 

        public override void OnActionExecuting(ActionExecutingContext filterContext)

        {

            // Ensure ASP.NET Simple Membership is initialized only once per app start

            LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);

        }

 

        private class SimpleMembershipInitializer

        {

            public SimpleMembershipInitializer()

            {

                Database.SetInitializer<UsersContext>(null);

 

                try

                {

                    using (var context = new UsersContext())

                    {

                        if (!context.Database.Exists())

                        {

                            // Create the SimpleMembership database without Entity Framework migration schema

                            ((IObjectContextAdapter)context).ObjectContext.CreateDatabase();

                        }

                    }

 

                    WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);

                }

                catch (Exception ex)

                {

                    throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex);

                }

            }

        }

    }

}

 

Now we can add view of account

1.     Login.cshtml

@model LoginAuthnticationSample.Models.LoginModel

 

@{

    ViewBag.Title = "Log in";

}

 

<br />

<br />

<br />

<div class="row">

    <div class="col-md-8 col-md-offset-2 well">

        @using (Html.BeginForm(new { ReturnUrl = ViewBag.ReturnUrl }))

        {

            @Html.AntiForgeryToken()

            @Html.ValidationSummary(true)

            <h2 class="text-center">Login</h2>

            <hr />

            <div class="row">

                <div class="col-md-12">

                    <div class="input-group">

                        <span class="input-group-addon">

                            <i class="glyphicon glyphicon-user"></i>

                        </span>

                        @Html.TextBoxFor(m => m.UserName, new { @class = "form-control", @placeholder = "ID" })

                        @Html.ValidationMessageFor(m => m.UserName)

                    </div>

                </div>

            </div>

            <div class="clearfix">&nbsp;</div>

            <div class="row">

                <div class="col-md-12">

                    <div class="input-group">

                        <span class="input-group-addon">

                            <i class="glyphicon glyphicon-lock"></i>

                        </span>

                        @Html.PasswordFor(m => m.Password, new { @class = "form-control", @placeholder = "Password" })

                        @Html.ValidationMessageFor(m => m.Password)

                    </div>

                </div>

            </div>

            <div class="clearfix">&nbsp;</div>

            <div class="row">

                <div class="col-md-12">

                    <span class="pull-left" style="margin-top:8px;">@Html.CheckBoxFor(m => m.RememberMe)&nbsp;&nbsp;</span><span class="pull-left"> @Html.LabelFor(m => m.RememberMe, new { @class = "checkbox" })</span>

                </div>

            </div>

            <div class="clearfix">&nbsp;</div>

            <div class="row">

                <div class="col-md-12">

                    <input type="submit" value="Login" class="form-control btn btn-info" />

                </div>

            </div>

            <div class="clearfix">&nbsp;</div>

            <p class="text-center">

                @Html.ActionLink("Register", "Register") if you don't have an account.

            </p>

            <div class="clearfix">&nbsp;</div>

        }

    </div>

</div>

 

@section Scripts {

    @Scripts.Render("~/bundles/jqueryval")

}

 

2.     Register.cshtml

 

@model LoginAuthnticationSample.Models.RegisterModel

@{

    ViewBag.Title = "Register";

}

 

<br />

<br />

<br />

<div class="row">

    <div class="col-md-8 col-md-offset-2 well">

        @using (Html.BeginForm())

        {

            @Html.AntiForgeryToken()

            @Html.ValidationSummary()

            <h2 class="text-center">Register</h2>

            <hr />

            <div class="row">

                <div class="col-md-12">

                    <div class="input-group">

                        <span class="input-group-addon">

                            <i class="glyphicon glyphicon-user"></i>

                        </span>

                        @Html.TextBoxFor(m => m.UserName, new { @class = "form-control", @placeholder = "User name" })

                    </div>

                </div>

            </div>

            <div class="clearfix">&nbsp;</div>

            <div class="row">

                <div class="col-md-12">

                    <div class="input-group">

                        <span class="input-group-addon">

                            <i class="glyphicon glyphicon-lock"></i>

                        </span>

                        @Html.PasswordFor(m => m.Password, new { @class = "form-control", @placeholder = "Password" })

                    </div>

                </div>

            </div>

            <div class="clearfix">&nbsp;</div>

            <div class="row">

                <div class="col-md-12">

                    <div class="input-group">

                        <span class="input-group-addon">

                            <i class="glyphicon glyphicon-lock"></i>

                        </span>

                        @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control", @placeholder = "Confirm password" })

                    </div>

                </div>

            </div>

            <div class="clearfix">&nbsp;</div>

            <div class="row">

                <div class="col-md-12">

                    <input type="submit" value="Register" class="form-control btn btn-info" />

                </div>

            </div>

            <div class="clearfix">&nbsp;</div>

            <div class="clearfix">&nbsp;</div>

        }

    </div>

</div>

 

@section Scripts {

    @Scripts.Render("~/bundles/jqueryval")

}

 

3.     Manage.cshtml

 

@model LoginAuthnticationSample.Models.LocalPasswordModel

@{

    ViewBag.Title = "Manage Account";

}

 

<p class="message-success">@ViewBag.StatusMessage</p>

 

<p>You're logged in as <strong>@User.Identity.Name</strong>.</p>

 

@if (ViewBag.HasLocalPassword)

{

    @Html.Partial("_ChangePasswordPartial")

}

else

{

    @Html.Partial("_SetPasswordPartial")

}

 

 

 

@section Scripts {

    @Scripts.Render("~/bundles/jqueryval")

}

 

4.     _ChangePasswordPartial.cshtml

 

@model LoginAuthnticationSample.Models.LocalPasswordModel

 

<br />

<br />

<br />

<div class="row">

    <div class="col-md-8 col-md-offset-2 well">

        @using (Html.BeginForm("Manage", "Account"))

        {

            @Html.AntiForgeryToken()

            @Html.ValidationSummary()

            <h2 class="text-center">Change Password</h2>

            <hr />

            <div class="row">

                <div class="col-md-12">

                    <div class="input-group">

                        <span class="input-group-addon">

                            <i class="glyphicon glyphicon-user"></i>

                        </span>

                        @Html.PasswordFor(m => m.OldPassword, new { @class = "form-control", @placeholder = "OldPassword" })

                    </div>

                </div>

            </div>

            <div class="clearfix">&nbsp;</div>

            <div class="row">

                <div class="col-md-12">

                    <div class="input-group">

                        <span class="input-group-addon">

                            <i class="glyphicon glyphicon-lock"></i>

                        </span>

                        @Html.PasswordFor(m => m.NewPassword, new { @class = "form-control", @placeholder =