Claims: Extranet user authentication made easy

I wanted to set up a site for external users. The site needed a public area with anonymous access and then secured areas for users authenticated via Form Based Authentication (FBA). As I have never done this before I was  happy to see the wealth of posts out there detailing the various approaches.

I did some reading and decided on the following approach:

  • Claims based web application
  • Top level site collection with anonymous access enabled (instructions, again one of many examples)
  • Sub-sites with anonymous access enabled

Here are some instructions to do this. One of many examples; Easy enough.

What I struggled with was the authentication method. By default the authentication goes to a new page, a page that would need its own styling (AFAIK). There are some examples out there of webparts that do the job but they all seemed a bit overly complicated to me. Here is my approach.

1. Create a new Visual Webpart in Visual Studio

2. Stick this in the WebPart class

        [WebBrowsable(true),
         Category(“Common”),
         WebDisplayName(“Redirect Page”),
         WebDescription(“The page to redirect user to once logged in”),
         Personalizable(PersonalizationScope.Shared)]
        public string RedirectPage{ get; set; }
        // Visual Studio might automatically update this path when you change the Visual Web Part project item.
        private const string _ascxPath = @”~/_CONTROLTEMPLATES/<FeatureName>/ExternalLogin/ExternalLoginUserControl.ascx”;
        protected override void CreateChildControls()
        {
            var control = Page.LoadControl(_ascxPath) as ExternalLoginUserControl;
            if (control != null)
            {
                control.RedirectPage = RedirectPage;
                Controls.Add(control);
            }
        }
3. Fire this into the user control ascx
<table>
<tr>
<td>User Name</td>
<td><asp:TextBox ID=”UserName” runat=”server”></asp:TextBox></td>
</tr>
<tr>
<td>Password</td>
<td><asp:TextBox ID=”Password” runat=”server” TextMode=”Password”></asp:TextBox></td>
</tr>
</table>
<asp:Button ID=”Login” runat=”server” Text=”Login” OnClick=”PerformLogin” />
<asp:Label runat=”server” ID=”ErrorMessage” style=”color:Red;”></asp:Label>
4. Shove this up the gullet of the ascx.cs file
public partial class ExternalLoginUserControl : UserControl
    {
        public string RedirectPage { get; set; }
        private static string ErrorText = “Incorrect Username or Password.”;
        protected void Page_Load(object sender, EventArgs e)
        {
            if ((SPContext.Current.Web.CurrentUser != null) &&
                (SPClaimProviderManager.IsEncodedClaim(SPContext.Current.Web.CurrentUser.LoginName)))
            {
                RedirectUser();
            }
        }
        protected void PerformLogin(object sender, EventArgs e)
        {
            try
            {
                if (SPClaimsUtility.AuthenticateFormsUser(new Uri(SPContext.Current.Web.Url), UserName.Text, Password.Text))
                {
                    RedirectUser();
                }
                else
                {
                    ReturnError();
                }
            }
            catch
            {
                ReturnError();
            }
        }
        private void RedirectUser()
        {
            Response.Redirect(RedirectPage);
        }
        private void ReturnError()
        {
            ErrorMessage.Text = ErrorText;
        }
    }
5. Deploy
6.  Add Webpart to page in the top level site.
There we go; extranet site with user login form without having to go to a seperate site.
P.S Sorry for the lack of comments in the code but it sort of speaks for itself.