Tuesday, May 10, 2011

Create a Forms Login Web Part for SharePoint 2010

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 PageThe LoginWebPart in the Solution ExplorerMicrosoft.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.LoginWebPart settings panelCreateChildControls 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.SPUtility class to redirect the user to the given ReturnUrl: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
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.

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
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?

Next, in the overridden
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
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:



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.