membershipReboot: getting started

MembershipReboot is a user identity management and authentication library. It is designed to encapsulate the important security logic while leaving most of the other aspects of account management either configurable or extensible for application developers to customize as needed. I’ll walk you through steps to follow to configure MembershipReboot.

Step 1:

Install the needed nuget packages:

  • Install-Package BrockAllen.MembershipReboot – This is the core package that contains the security logic.
  • Install-Package BrockAllen.MembershipReboot.Ef – This package contains implementation on the user account data is persisted.
  • Install-Package BrockAllen.MembershipReboot.WebHost – Handles the authentication logic. Contains logic that handles issuing of cookies to track the logged in user.

Step 2:

Add configurations to the web.config

<configuration>

<configSections>

<!-- // ...... // -->

<section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
<section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
<section name="membershipReboot" type="BrockAllen.MembershipReboot.SecuritySettings, BrockAllen.MembershipReboot" />

<!-- // ...... // -->

</configSections>

<!-- // MembershipReboot Security configuration // -->

<membershipReboot 
requireAccountVerification="true"
emailIsUsername="false" 
multiTenant="false" 
passwordHashingIterationCount="0" 
accountLockoutDuration="00:01:00" 
passwordResetFrequency="0" />

<!-- // connection string name is MembershipReboot by default, but can be changed. If changed, the name should be passed as constructor argument to the DefaultUserAccountRepository // -->

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

<!-- // ...... // -->

<system.web>

<!-- // enable forms authentication // -->

<authentication mode="Forms">
<forms loginUrl="~/UserAccount/Login"></forms>
</authentication>

<!-- // ...... // -->

</system.web>

<system.webServer>

<!-- // WIF Session Authentication Module // -->

<modules>
<add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
</modules>

<!-- // ...... // -->

</system.webServer>

<system.net>

<mailSettings>
<smtp deliveryMethod="Network" from="no-reply@mydomain.org">
<network host="smtp.mymailserver.com" port="587" userName="someone@mydomain.org" password="mypassword" enableSsl="true" />
</smtp>
</mailSettings>

</system.net>

<system.identityModel.services>
<federationConfiguration>
<cookieHandler requireSsl="false" /> <!-- // set to true before deploying to production server // -->
</federationConfiguration>
</system.identityModel.services>

<!-- // ...... // -->

</configuration>

Step 3:
Install Ninject for MVC and register services for MembershipReboot (any other IOC container would serve the purpose).

Install-Package Ninject.MVC5

Register dependencies:

Database.SetInitializer(new MigrateDatabaseToLatestVersion<DefaultMembershipRebootDatabase, BrockAllen.MembershipReboot.Ef.Migrations.Configuration>());

kernel.Bind<UserAccountService>().ToSelf();
kernel.Bind<AuthenticationService>().To<SamAuthenticationService>();
kernel.Bind<IUserAccountQuery>().To<DefaultUserAccountRepository>().InRequestScope();
kernel.Bind<IUserAccountRepository>().To<DefaultUserAccountRepository>().InRequestScope();

Step 4:

Add controllers and actions to handle your needs.

public class UserAccountController : Controller
    {
        UserAccountService _userAccountService;
        AuthenticationService _authService;

        public UserAccountController(AuthenticationService authService)
        {
            _userAccountService = authService.UserAccountService;
            _authService = authService;
        }
        //
        // GET: /UserAccount/
        [Authorize]
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult Login()
        {
            return View(new LoginInputModel());
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Login(LoginInputModel model)
        {
            if (ModelState.IsValid)
            {
                BrockAllen.MembershipReboot.UserAccount account;
                if (_userAccountService.AuthenticateWithUsernameOrEmail(model.Username, model.Password, out account))
                {
                    _authService.SignIn(account, model.RememberMe);

                    if (account.RequiresTwoFactorAuthCodeToSignIn())
                    {
                        return RedirectToAction("TwoFactorAuthCodeLogin");
                    }
                    if (account.RequiresTwoFactorCertificateToSignIn())
                    {
                        return RedirectToAction("CertificateLogin");
                    }                    

                    if (_userAccountService.IsPasswordExpired(account))
                    {
                        return RedirectToAction("Index", "ChangePassword");
                    }

                    if (Url.IsLocalUrl(model.ReturnUrl))
                    {
                        return Redirect(model.ReturnUrl);
                    }

                    return RedirectToAction("Index");
                }
                else
                {
                    ModelState.AddModelError("", "Invalid Username or Password");
                }
            }

            return View(model);
        }

        public ActionResult Register()
        {
            return View(new RegisterInputModel());
        }

        [ValidateAntiForgeryToken]
        [HttpPost]
        public ActionResult Register(RegisterInputModel model)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    var account = _userAccountService.CreateAccount(model.Username, model.Password, model.Email);
                    ViewData["RequireAccountVerification"] = _userAccountService.Configuration.RequireAccountVerification;
                    return View("Success", model);
                }
                catch (ValidationException ex)
                {
                    ModelState.AddModelError("", ex.Message);
                }
            }
            return View(model);
        }
    }

Update
See the configuration section from the documentation for more details on configuration settings.

Advertisements

12 thoughts on “membershipReboot: getting started

      1. I have the same question. Here’s a clarification:
        Where should I be adding those packages? TO my web/mvc project or to my Core Domain project, or my Infrastructure project (where my EF code exists)?

        I want my “user” domain object to be in the core project, but all the EF-related code and services to exist in the infrastructure project.

        1. You should have them installed in your web/mvc project since you’re installing these packages and not creating classes from scratch. If you’re creating classes to replace certain classes/inteface in MR, then I think it’s a good option to separate into appropriate layers.

          “I want my “user” domain object to be in the core project” – You should model your User domain object separate from MR’s representation of a User so you don’t couple your domain logic/application to MR (What if you decide to switch from MR to another similar framework).

          1. 2 more question based on your response:

            1) you say “add MR to the web/mvc project’. However, my DbContext is in my Infrastructure project. If I add MR.EF package to web, now I will end up with a 2nd db context, is that not correct? Also that means my MR user would be in the web project, and if I ever needed to reference that user object in my infrastructure I would introduce cyclical references as web depends on infrastructure, and infrastructure would now depend on web also.

            2) If I separate my User domain model from the MR user, how do I then tie those together? When the user authenticates thru MR, I would have to know what Domain user corresponds to that MR user.

  1. I had to add the following to start getting registration verification email:
    var config = MembershipRebootConfig.Create();
    kernel.Bind().ToConstant(config);

    This can be added to step 3

  2. Thank you so much to the guide. I’ve tried to implement it but am having problems as I’m using StructureMap for MVC5 instead of Ninject. Is it possible to show me how to change the above for StructureMap? Thank you for your time.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s