• Published
  • 4 min

Authenticate users from different sources

<p>A blog post about how you can do authorization from multiple sources</p>

In a project we were working on in Epinova, we had to separate customer authorization and EPiServer authorization. We wanted to use the windows membership- and role-provider to authorize EPiServer users, and a custom customer membership provider we developed for authorizing customers. It was not an option to have customer information in our EPiServer database.

There is no official EPiServer way to do this, so this is simply an overview of what we did to solve it.  Hopefully, some of you will find this useful :-)

We met the first obstacle in the web.config file when we tried to change the loginUrl setting in the tag:
<authentication mode="Forms">
   <forms name=".EPiServerLogin" loginUrl="/Util/Login.aspx" timeout="120" />
</authentication>

EPiServer is depended on this tag to make the EPiServer login work, so we decided to leave it alone. We created our windows groups and set up EPiServer authorization and group rights as normal.

As described above, we developed a custom customer membership provider and added it to the <membership> section in the web.config file. But, we kept WindwosMembershipProvider as the default provider. We created a boolean dynamic property which we set to true on the pages that required customer authorization. The pages where this property is set, has functionality on the pages that are dependent on a customer object that is initialized on authorization. We created a custom Login.aspx page that contains an asp:Login control which authenticates user against the customer membership provider. In addition, we added a property on the start page which contains the path to the custom Login.aspx page.

To enable EPiServer look-alike functionality, we catch the OnLoggedIn event and redirect the user back to the page he/she was trying to access before they were sent to the custom login page. The method looks like this:
protected void CustomerLoginControl_OnLoggedIn(object sender, EventArgs e)
{
    int pageId = -1;
    string returnUrl = Request.QueryString["returnurl"];
    if (!string.IsNullOrEmpty(returnUrl))
    {
       int.TryParse(returnUrl, out pageId);
    }
    if(pageId >0)
    {
       PageData returnPage = GetPage(new PageReference(pageId));
       Response.Redirect(returnPage.StaticLinkURL);
    }
    Response.Redirect("/");
}

After doing this, we created a simple custom boolean property which you can read about in my post “Custom boolean property”. The reason for doing this is that we needed a boolean dynamic property which we could reset in the EPiServer page tree. As you probably know, it is not possible to reset the default EPiServer boolean property.

All the pages we created in the solution inherit from the baseclass EPiPageBase which again inherits from EPiServer.TemplatePage. To implement our custom authorization method, we override the OnPreInit method like this:
protected override void OnPreInit(EventArgs e)
{
    base.OnPreInit(e);
    if (this.CurrentPage != null)
    {
       if (PageRequireCustomerAuth (this.CurrentPage))
       {
          VerifyAuthenticatedOrRedirectToLogin();
       }
    }
}

First, we check if the page requires customer authentication in the method PageRequireCustomerAuth. This method retrieves the dynamic property and checks its value. If the dynamic property is not set or it is set to 0 it returns false, and true otherwise. (0 is “false” in our custom boolean property)  For pages that require customer authentication, we call the VerifyAuthenticatedOrRedirectToLogin method. This method has three purposes:
- if the user is authenticated as a customer, let them access the page
- if the user is authenticated as a EPiServer user, redirect him/her to an information page describing the difference between being logged on as an EPiServer user and customer user
- if the user is not authenticated, redirect him/her to the custom customer login page

The pseudo code looks like this:
private void VerifyAuthenticatedOrRedirectToLogin()
{
    if (User.Identity.IsAuthenticated)
    {
       // The user is authenticated. Find out whether he/she is authenticated as  customer or EPiServer user
       if (User.IsInRole("WebEditors") || User.IsInRole("WedAdmins")) 
       {
          // Users authenticated as EPiServer users are redirected to an information page
          // Get redirect url
          // Response.Redirect(redirect url);
       }
       // If we get here, the user is logged on as a customer, so everything is as it should be :)
    }
    else
    {
       // The user is not authenticated, so we redirect to the customer login.aspx page. (We get the url from the start page property)
       // The reason we include the CurrentPageLink, is to make the OnLoggedIn event work correctly, so we are able to redirect the user back to the page he/she is accessing
       var customerLoginUrl = GetCustomerLoginUrl();
       string separator = "?";
       if(customerLoginUrl.Contains("?"))
       {
          separator = "&";
       }
       Response.Redirect(customerLoginUrl + separator +"returnurl=" + CurrentPageLink);
    }
}

This should give you the opportunity to keep your EPiServer authentication untouched, and still be able to authenticate other users through your custom membership provider.