Stop Panicking and Create a Forms Login Web Part for SharePoint 2010

Posted: Jon | Comments: 15 | October 29th, 2010
Oct 29

On your way to branding a public-facing SharePoint 2010 site, you may at some point find yourself eye-to-eye with its bare, unfeeling, and unskinnable default login page. Giving life to this page is a dicey affair—it is located under the _login directory in the hive, way outside the jurisdiction of your site’s master pages. It uses the simple.master master page, which, from a design standpoint, might as well be an empty text file.

Default SharePoint 2010 Login Page

If you should find yourself facing such a task, do not panic. Rather, reach slowly for Visual Studio 2010 and follow along at home–we’re going to build a Forms Login Web Part that can handle the same authenticatory task in much more design-friendly surroundings.

First, we’ll create an Empty SharePoint Project, and add a Web Part to it. Let’s call it LoginWebPart.

The LoginWebPart in the Solution Explorer

Be sure to select Web Part, and not Visual Web Part. Sure, it’s neato-torpedo to be able to build web parts visually, and nine times out of ten that’s going to be a better fit for what you will be up against in a custom SharePoint development scenario. But for this little adventure, it throws in a sopping heap of clutter that we’d just end up having to slice out in the end.

Let’s right-click on our project and add a reference to the Microsoft.SharePoint.IdentityModel library. This avails to us the SPClaimsUtility class, which houses a method that nicely black-boxes the messy logging-in part of our exercise. Look sharp, though—this evasive batch of IL doesn’t appear on the Add Reference dialog’s regular assemblies menu. Instead, you will have to browse from the dialog to the find the DLL under C:\Windows\assembly\GAC_MSIL\Microsoft.SharePoint.IdentityModel\14.0.0.0__71e9bce111e9429c.

Now, we crack open our web part’s code-behind file (LoginWebPart.cs) and add a ReturnUrl property. This allows the user editing the page to specify a redirect URL for successful login attempts.

private string _returnUrl;
/// <summary>
/// Gets or sets the URL to redirect to
/// upon successful sign in.
/// </summary>
/// <value></value>
/// <returns></returns>
/// <remarks></remarks>
[Personalizable(PersonalizationScope.Shared),
    WebBrowsable(true),
    Category("Behavior"),
    WebDisplayName("Return URL"),
    WebDescription("The URL to which users are redirected upon successfully signing in.")]
public string ReturnUrl
{
    get
    {
        if ((string.IsNullOrEmpty(_returnUrl)))
            _returnUrl = this.Page.Request["ReturnUrl"];

        return _returnUrl;
    }
    set
    {
        _returnUrl = value;
    }
}

Those attributes decorating the property make it available for editing in the web part’s settings panel. See?

LoginWebPart settings panel

Next, in the overridden CreateChildControls method so thoughtfully provided by our IDE, we want to add a standard ASP.NET Login control, tweak a couple of key properties, and add handler methods for its Authenticate and LoggedIn events.

protected override void CreateChildControls()
{
    // create a login control
    var loginControl = new Login();

    // hide the Remember Me checkbox
    loginControl.DisplayRememberMe = false;

    // hide the control if the User is already logged in
    loginControl.Visible = !this.Page.User.Identity.IsAuthenticated;

    // add event handlers
    loginControl.Authenticate += new AuthenticateEventHandler(loginControl_Authenticate);
    loginControl.LoggedIn += new EventHandler(loginControl_LoggedIn);

    Controls.Add(loginControl);
}

In the Authenticate event handler method, we use the aforementioned SPClaimsUtility class to validate the user’s credentials:

void loginControl_Authenticate(object sender, AuthenticateEventArgs e)
{
    // validate credentials
    var login = (sender as Login);
    e.Authenticated = SPClaimsUtility.AuthenticateFormsUser(
        this.Page.Request.Url, login.UserName, login.Password);
}

Lastly, in the LoggedIn event, we will use the SPUtility class to redirect the user to the given ReturnUrl:

void loginControl_LoggedIn(object sender, EventArgs e)
{
    // redirect to ReturnUrl
    SPUtility.Redirect(
        this.ReturnUrl, SPRedirectFlags.Default, this.Context);
}

After deploying this to our site, we will find the LoginWebPart under the Custom category when adding a web part to a page:

Adding the Login Web Part.

We can now place this web part anywhere in the site—preferably in an anonymously accessible area. I suppose if you were really touched in the head, you could secure it, too.

webpart

Take a deep cleansing breath and forget about the barren default login page—our new Login Web Part lets us place a security prompt within reach of our branded master page, perhaps even with other public content. It gives us more control and flexibility in the arrangement of our site, which may in fact be the whole thrust of Web Parts in the first place.

15 comments
  1. ismartypants.com says:

    I came across your webpage from twitter and it really is pretty informative. Thanks for discussing this kind of an incredible article.

  2. Cake Convention says:

    Keep up the good work – for sure i will check out more posts.

  3. Fall Foliage Tours says:

    You seem to know a lot about this. This is good blog. A great read. I’ll certainly be back.

  4. Salmon Derby says:

    Any update on this ? Excellent information keep it up!

  5. Ryan Terry says:

    Wow this was very helpful! So how do we go about using the “Remember Me” feature? is that built in? Thanks :)

  6. Douglas Gummer says:

    I found this post very informative which I found on yahoo. I bookmarked your blog. Thanks for sharing.

  7. jason robertson says:

    Hi great post I have implmented this however on the Sign Out the pages errors crashes

    I know why and its related to the Federated Authorisation cookie used by claims I have also seen posts to fix this implemented on a login status control however with out adding this and overriding / replacing the existing Sign Out is there another way or reason for this

    [ArgumentException: Exception of type 'System.ArgumentException' was thrown.
    Parameter name: encodedValue]
    Microsoft.SharePoint.Administration.Claims.SPClaimEncodingManager.DecodeClaimFromFormsSuffix(String encodedValue) +25840358
    Microsoft.SharePoint.Administration.Claims.SPClaimProviderManager.GetProviderUserKey(String encodedSuffix) +73
    Microsoft.SharePoint.SPGlobal.CreateSPRequestAndSetIdentity(SPSite site, String name, Boolean bNotGlobalAdminCode, String strUrl, Boolean bNotAddToContext, Byte[] UserToken, String userName, Boolean bIgnoreTokenTimeout, Boolean bAsAnonymous) +27266953
    Microsoft.SharePoint.SPWeb.InitializeSPRequest() +223
    Microsoft.SharePoint.WebControls.SPControl.EnsureSPWebRequest(SPWeb web) +365
    Microsoft.SharePoint.WebControls.SPControl.SPWebEnsureSPControl(HttpContext context) +520
    Microsoft.SharePoint.ApplicationRuntime.SPRequestModule.GetContextWeb(HttpContext context) +27
    Microsoft.SharePoint.ApplicationRuntime.SPRequestModule.PostResolveRequestCacheHandler(Object oSender, EventArgs ea) +918
    System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +80
    System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +171

  8. Dhawal says:

    thank you for the solution. When I am trying to add the webpart to the page. it gives me “An error occured while attempting to add the item to the page”. Would you have any clue regarding this?
    In the debug mode: A first chance exception of type ‘System.NullReferenceException’ occurred in WebParts.dll is the error. Any suggestions?

    • Gurujimani says:

      Hi Dhawal,

      I am receiving the same error as you reported. Did you manage to resolve this issue? Hope you did.

      Kindly reply if you have any solution for this error.

      Thanks.

  9. todd barber says:

    I am having the same error as Dhawal. Any ideas?

  10. Gurujimani says:

    Hi,

    Thank you for this post. I am receiving the same error as reported by @Dhawal. So, I was not able to add the webpart to the page. Is there any solution for this error?

    Thanks.

  11. Arijit says:

    @above…….
    Please Try this…
    replace >>> private string _returnUrl;
    with >>>>private string _returnUrl=”http://your site redirection url after login”;
    I am not sure about exact reason.But somehow when you add the webpart, the webpart code is in running state.So It says null reference for the property >>>.ReturnUrl (since it’s not initialized yet) and you are using in this line>>>SPUtility.Redirect(this.ReturnUrl, SPRedirectFlags.Default, this.Context);

    and comment the part>>>> loginControl.Visible = !this.Page.User.Identity.IsAuthenticated;
    because when you will add the webpart then it is already logged in as administrator.
    So if you are already logged in this statement will make invisible the control.

  12. Bharat Sukhwal says:

    Replace the code with below code to add the web part on the page

    if (!(string.IsNullOrEmpty(_returnUrl)))
    _returnUrl = this.Page.Request["ReturnUrl"];

  13. referencement internet says:

    Hi, Neat post. There’s an issue with your website in web explorer, would check this? IE nonetheless is the marketplace leader and a large portion of other folks will leave out your fantastic writing due to this problem.

Leave a Comment