When using FBA in SharePoint 2010 you get the error message below on login when the user name and/or password is incorrect.
You get the same error message when the user account is locked out, which is not very useful in helping the user understands why his/her login isn’t working.
Ideally, a message like below should be displayed for locked out accounts:
The rest of this post describes how you can do this.
1. Create custom login page
First we need a custom login page. You’d typically approach this by copying the OOTB login page at {SharePointRoot}\TEMPLATE\IDENTITYMODEL\FORMS\Default.aspx and then modify it.
Create an empty SharePoint project in Visual Studio (mine is called CustomLoginPage) and add a ‘SharePoint “Layouts” Mapped Folder‘ to the project. This will also add a sub-folder (underneath the mapped Layouts folder) with the same name as the project. Right click on this sub-folder and add an existing item. Browse to and select {SharePointRoot}\TEMPLATE\IDENTITYMODEL\FORMS\default.aspx. In Visual Studio, rename this file to login.aspx.
Right click on the sub-folder again and add a class name login.aspx.cs.
Your project should now look like below.
2. Hook up the custom login page to the code-behind
The OOTB login page uses the class Microsoft.SharePoint.IdentityModel.Pages.FormsSignInPage as its code-behind. We will now update our custom login page to use our custom code-behind (which will inherit from the OOTB class).
Edit the login.aspx file and look for Page directive, which should look like below:
<%@ Page Language="C#" Inherits="Microsoft.SharePoint.IdentityModel.Pages.FormsSignInPage" MasterPageFile="~/_layouts/simple.master" %>
Change the Inherits attribute to point to our login class, which should be “CustomLoginPage.Layouts.CustomLoginPage.login” if you have followed the steps so far exactly.
We also need to add an Assembly directive to the top of the page, like below (your assembly strong name will be different):
<%@ Assembly Name="CustomLoginPage, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cd31ba2a5f8163e5" %>
Now, we are going to make our code-behind inherits from the OOTB FormsSignInPage class. Add a reference to the following assemblies to the project:
- Microsoft.SharePoint.IdentityModel.dll (can be found under C:\Windows\assembly\GAC_MSIL\Microsoft.SharePoint.IdentityModel\14.0.0.0__71e9bce111e9429c)
- System.Web.dll (can be found under C:\Windows\Microsoft.NET\Framework\v2.0.50727)
Edit the login.aspx.cs file. Change the class to be public and make it inherits from FormsSignInPage, which is defined in the Microsoft.SharePoint.IdentityModel.Pages namespace.
3. Add code to detect when user is locked out
The OOTB FormsSignInPage uses a standard ASP.NET Login control. As we have inherited from this class, this control is also available to us.
The ASP.NET Login control has a LoginError event, which fires when a login failed. We will hook in to this event to detect if the user is locked out, and if so, alter the default error message to something more helpful.
Add the following code to the class and review the in-code comments:
protected override void OnLoad(EventArgs e) { //Ensure to call base.OnLoad(e) so all the other OOTB initialisation can take place base.OnLoad(e); base.signInControl.LoginError += new EventHandler(signInControl_LoginError); //Revert back to the default message on each load base.signInControl.FailureText = "The server could not sign you in. Make sure your user name and password are correct, and then try again."; } void signInControl_LoginError(object sender, EventArgs e) { //Verify if the failure is because the account is locked out. If so, display a more meaningful error message. var provider = this.CurrentMembershipProvider; var user = provider.GetUser(this.signInControl.UserName, false); if (user != null && user.IsLockedOut) { base.signInControl.FailureText = "The specified account is locked out. Please contact your system administrator."; } } private MembershipProvider CurrentMembershipProvider { get { return Membership.Providers[base.Site.WebApplication.IisSettings[0].FormsClaimsAuthenticationProvider.MembershipProvider]; } }
One interesting thing about the code above is the CurrentMembershipProvider property. Your web app is likely to have multiple membership providers defined. The default one is named ‘i‘, and the other is the one you would have manually configured in web.config and specified in Central Admin. In the code you need to explicitly reference the provider that you want to use, and you can use the code as shown above to do this without hardcoding the provider name.
That’s all the coding. Go ahead and deploy your solution.
4. Configure your web app to use the custom login page
Configuring FBA is beyond the scope of this post, but ensure the following:
- Claim and FBA is enabled for your web app
- Your membership provider is configured in the various web.config files
- Your web app in Central Admin is configured to use the membership provider you configured in the web.config
- You configured the web app to use a “Custom Sign In Page“, such as /_layouts/customloginpage/login.aspx in this example
Hello, great post and this is exactly what i need. However, I find it very difficult to follow the steps, for example adding assembly directive, changing class to public and make it inherit from formsigninpage, etc… if you have time, would you be able to please provide some additional steps? i can’t find any other posts such as this one that would allow me to do the same thing… thanks for all your help in advance.