A Client-side Ajax Login for ASP.NET

A question was posed on the ASP.NET forums recently asking how to have a login control that doesn’t refresh the page.  The ideal solution would be to just drop an ASP.NET Login control inside an updatepanel.  However, the Login control (along with PasswordRecovery, ChangePassword, and CreateUserWizard controls whose contents have not been converted to editable templates) is not supported inside an UpdatePanel.  They are just not compatible with partial-page updates.

The ASP.NET AJAX Library does include a proxy class that allows client-side authentication, the Sys.Services.AuthenticationService Class!  We can therefore create a very simple and straight-forward “roll-your-own” login solution that does not require a full postback.

Getting Started:

I am going to assume that you have completed all of the normal, necessary steps to allow authentication, but the authentication service is not enabled by default.  You must enable it in the web.config file.  Add the following to your web.config within the <configuration> section:

  <system.web.extensions>
    <scripting>
      <webServices>
        <authenticationService enabled="true" requireSSL="false"/>
      </webServices>
    </scripting>
  </system.web.extensions>

Next, create two DIVs on your page:  one for the “anonymous view” and one for the “logged-in view”.  Set the the display for both DIVs to ‘none’.

  <div id="AnonymousView" style="display: none;">
      <input id="txtUsername" type="text" /><br />
      <input id="pwdPassword" type="password" /><br />
      <input id="chkRememberMe" type="checkbox" />Remember Me<br />
      <input id="btnLogIn" type="button" value="Log In" />
  </div>
  <div id="LoggedInView" style="display: none;">
      Logged in.<br />
      <input id="btnLogOut" type="button" value="Log Out" />
  </div>

The get_isLoggedIn() property of the class then allows you to show and hide the DIVs appropriately.

  var ssa = Sys.Services.AuthenticationService;
  if (ssa.get_isLoggedIn()) {
      $get('LoggedInView').style.display = '';
  } else {
      $get('AnonymousView').style.display = '';
  }

The Complete Code:

  <body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server" />
        <div id="AnonymousView" style="display: none;">
            <input id="txtUsername" type="text" /><br />
            <input id="pwdPassword" type="password" /><br />
            <input id="chkRememberMe" type="checkbox" />Remember Me<br />
            <input id="btnLogIn" type="button" value="Log In" />
        </div>
        <div id="LoggedInView" style="display: none;">
            Logged in.<br />
            <input id="btnLogOut" type="button" value="Log Out" />
        </div>
    </form>
</body>
        <script type="text/javascript">
            // Hook up the click events of the log in and log out buttons.
            $addHandler($get('btnLogIn'), 'click', loginHandler);
            $addHandler($get('btnLogOut'), 'click', logoutHandler);
            var ssa = Sys.Services.AuthenticationService;
            if (ssa.get_isLoggedIn()) {
                $get('LoggedInView').style.display = '';
            } else {
                $get('AnonymousView').style.display = '';
            }
           
            function loginHandler() {
                var username = $get('txtUsername').value;
                var password = $get('pwdPassword').value;
                var isPersistent = $get('chkRememberMe').checked;
                var customInfo = null;
                var redirectUrl = null;
                // Log them in.
                ssa.login(username,
                          password,
                          isPersistent,
                          customInfo,
                          redirectUrl,
                          onLoginComplete,
                          onError);
            }
           
            function logoutHandler() {
                // Log them out.
                var redirectUrl = null;
                var userContext = null;
                ssa.logout(redirectUrl,
                           onLogoutComplete,
                           onError,
                           userContext);
            }
           
            function onLoginComplete(result, context, methodName) {
                // Logged in.  Hide the anonymous view.
                $get('LoggedInView').style.display = '';
                $get('AnonymousView').style.display = 'none';
            }
           
            function onLogoutComplete(result, context, methodName) {
                // Logged out.  Hide the logged in view.
                $get('LoggedInView').style.display = 'none';
                $get('AnonymousView').style.display = '';
            }
           
            function onError(error, context, methodName) {
                alert(error.get_message());
            }
         
        </script>

Comments and Possible Enhancements:

  • There will always be a page refresh on logout.  This is necessary to ensure that any user-specific information is cleared from the page.
  • You can place the two DIVs inside a third DIV and style that, thus showing a consistant style (width, height, border, etc.) for both child DIVs.
  • You will have probably noticed that there is a redirectUrl parameter for both the login() and logout() methods.  This, along with querystring parameters, could easily be adapted to create a login page that users are redirected to for authentication and redirected from once logged in.  

References:

http://asp.net/ajax/documentation/live/ClientReference/Sys.Services/AuthenticationServiceClass/default.aspx

No Comments