Using two Membership Providers for ASP.NET logins

I quite like the Microsoft Membership Framework for handling membership roles, authentication, and security resources in ASP.NET applications. It’s easy to create the initial user login and management framework for a new application, then swap in a more sophisticated Provider as needed.

For my current project, we have a new requirement to allow logins against multiple user stores. The existing application validates against an Active Directory store. But for a subset of users, there is a need to check if they are in a SQL Server database and allow them to login while they wait for their Active Directory setup to complete. This SQL Server also contains a secondary set of roles that will be relevant for any user that is in the SQL Server user store, regardless of whether they were validated via AD or the SQL Server.

The first step I took was to figure out the easiest way to have two separate providers to validate the user. You can configure as many membership providers as you want in the web.config for your application, but you choose a default provider as part of the setup. If you use the standard Login control, it will only check against that default provider.

In order to change that behavior, I overrode the Login.Authenticate event for my Login control. The method looks a little like this:

    protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)
    {
        bool foundUser = false;
        List<string> roles = new List<string>();
        roles.Add("GeneralUser");
        // this will call the default MembershipProvider
        if (Membership.Provider.ValidateUser(LoginBox.UserName, LoginBox.Password))
        {
            foundUser = true;
            // do any additional lookups for this type of user (Default MembershipProvider) here
        } // otherwise, explicitly call secondary provider
        else if (
            Membership.Providers["SecondarySqlMembershipProvider"].ValidateUser(LoginBox.UserName,
                                                                                LoginBox.Password))
        {
            foundUser = true;
            roles.Add("SecondaryUser");
            // do any additional lookups relevant to this type of user
        }
        if (foundUser)
        {
            Session["UserId"] = LoginBox.UserName;
            Session["Groups"] = roles;
        }
        e.Authenticated = foundUser;
    }

I didn’t need to modify the Authentication Ticket or cookie, so I could rely on the Membership Framework to handle the rest. If I need to add additional information, I can do it in the commented spots to correctly handle the type of user I care about.

18 thoughts on “Using two Membership Providers for ASP.NET logins

  1. Pingback: Using two membership providers - Duck Bytes

  2. Pingback: Duck Under » Using two ASP.NET membership providers

  3. Cdr. Beavis

    So, I’m assuming that I just add “SecondarySqlMembershipProvider” into the section of the element in the web.config?

    Thanks,
    -B

  4. stevi Post author

    Cdr. Beavis,

    Correct. In your system.web/membership/providers section of your web.config, use the add element to configure your membership providers, one element per provider. Then set the default provider in your membership element, “defaultProvider” attribute.

  5. David

    Was wondering… would this work with windows integrated auth on the page?

    So, asp.net tried to auth using windows integrated/AD first, then fall back to SQL integrated?

    Or am I missing some detail?

  6. stevi Post author

    David,
    Yes, that’s pretty much what I was doing in the case where this came up.

    The default membership provider was the System.Web.Security.ActiveDirectoryMembershipProvider.

    Only if that attempt to authorize fail would the Login control attempt to use the System.Web.Security.SqlMembershipProvider, which was listed in system.web/membership/providers in the web.config with the name “SecondarySqlMembershipProvider”

  7. MGarfield

    The login code worked perfectly! Thanks for publishing the user login solution. I changed just a few lines but the rest was stright forward.

  8. paul

    I like your idea, but you know, it’d be even more extensible if you just iterate over your providers, rather than calling those two specifically.

  9. stevi Post author

    Paul,
    That’s certainly possible, although I’ve yet to see a case of more than two membership providers.

    Were I to go to n > 2, I’d probably switch to some sort of factory pattern to handle the various unique elements of each membership provider, to avoid a large if/then or case statement in the Login.Authenticate method.

  10. Greg

    My login is working but my Page.User.Identity.Name == “”. How do I populate the page User when overriding the Authenticate method like this?

  11. Robert J. Bullock

    For some reason, I can’t get to the username/password controls in the Login1_Authenticate event… “LoginBox” isn’t there.

  12. AndrewH

    You could also consider moving this down a layer. You could create a custom provider that wraps the logic of trying multiple stores (through the existing providers.)

    By creating a custom provider that wraps the existing providers you need not change the user interface code at all. This centralises your logic and can even be reused between systems, if needs be.

  13. David

    Hi Steve

    This does not seem ot be catching the validation, it just uses the default, what have i missed?

    Hear from you soon

    Dave

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>