November 28, 2014
Hot Topics:

Asynchronous, High-Performance Login for Web Farms

  • December 26, 2007
  • By Udi Dahan
  • Send Email »
  • More Articles »

And the code that the web server runs on startup looks like this (assuming constructor injection):

public class UserAuthenticationServiceAgent
{
   public UserAuthenticationServiceAgent(IBus bus)
   {
      this.bus = bus;
      // subscribe for updates
      bus.Subscribe(typeof(UsernameInUseMessage));
      // request the full list
      bus.Send(new GetAllUsernamesMessages());
   }

}

When the Authentication Service receives the GetAllUsernamesMessage, its message handler accesses its cache of usernames and hashed passwords, and builds a message that is returned to the caller as follows:

public class GetAllUsernamesMessageHandler :
   BaseMessageHandler<GetAllUsernamesMessage>
{
   public override void Handle(GetAllUsernamesMessage message)
   {
      this.Bus.Reply(Cache.GetAll<UsernameInUseMessage>());
   }
}

And the class on the web server that handles a UsernameInUseMessage when it arrives:

public class UsernameInUseMessageHandler :
   BaseMessageHandler<UsernameInUseMessage>
{
   public override void Handle(UsernameInUseMessage message)
   {
      WebCache.SaveOrUpdate(message.Username, message.HashedPassword);
   }
}

When the app server sends the full list, multiple objects of the type UsernameInUseMessage are sent in one physical message to that web server. However, the bus object that runs on the web server dispatches each of these logical messages one at a time to the message handler above.

So, when it comes time to actually authenticate a user, this the web page (or controller, if you're doing MVC) would call:

public class UserAuthenticationServiceAgent
{
   public bool Authenticate(string username, string password)
   {
      byte[] existingHashedPassword = WebCache[username];
      if (existingHashedPassword != null)
         return existingHashedPassword == this.Hash(password);

      return false;
   }
}

When registering a new user, the web server would of course first check its cache, and then send a RegisterUserMessage that contained the username and the hashed password.

[Serializable]
[StartsWorkflow]
public class RegisterUserMessage : IMessage
{
   private string username;
   public string Username
   {
      get { return username; }
      set { username = value; }
   }

   private string email;
   public string Email
   {
      get { return email; }
      set { email = value; }
   }

   private byte[] hashedPassword;
   public byte[] HashedPassword
   {
      get { return hashedPassword; }
      set { hashedPassword = value; }
   }
}

When the RegisterUserMessage arrives at the app server, a new long-running workflow is kicked off to handle the process:

public class RegisterUserWorkflow :
   BaseWorkflow<RegisterUserMessage>,
   IMessageHandler<UserValidatedMessage>
{
   public void Handle(RegisterUserMessage message)
   {
      //send validation request to message.Email containing
      // this.Id (a guid) as a part of the URL
   }

   /// <summary>
   /// When a user clicks the validation link in the email, the
   /// web server sends a UserValidatedMessage containing the
   /// workflow Id
   /// </summary>
   public void Handle(UserValidatedMessage message)
   {
      // write user to the DB

      this.Bus.Publish(new UsernameInUseMessage(
         message.Username, message.HashedPassword));
   }
}

That UsernameInUseMessage would eventually arrive at all the web servers subscribed.





Page 2 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel