My Blog On .NET

and some other stuff too
posts - 18, comments - 6, trackbacks - 2

Thursday, May 22, 2008

Creating a custom Principal and Identity for Silverlight 2

I've been spending some time exploring Silverlight 2 and having a great time doing so. The more I work with it the more I realize its potential at being a game changer for creating Internet applications. The focus I have had is not so much on the rich eye popping user experience it can create, but more on how to build real world business applications. So after getting my head around using web services within Silverlight I began to explore role-based security. I came across an excelling blog post by Brad Abrams entitled "Accessing the ASP.NET Authentication, Profile and Role Service in Silverlight". It is a great example on how to use WCF to authenticate a user within a Silverlight application using the ASP.NET application services. However with Silverlight truly being a client-side application and not a stateless web page I wanted to see if there was support for a Principal and Identity objects much like we having in Windows and ASP.NET. What I found is that there are no classes implemented within the CLR used by Silverlight not even the GenericPrincipal and GenericIdentity but the interfaces IPrincipal and IIdentity are there to create our own.

To see how I did this you can download the source code here.

In the SilverlightPrincipalDemo project I added two classes called SilverlightPrincipal and SilverlightIdentity that each implement IPrincipal and IIdentity respectively. The SilverlightPrincipal class like other principal classes under the .NET framework will represent the identity and the roles of a user. These classes will also encapsulate the service calls to authenticate a user and retrieve the roles the user belongs to. Since Silverlight will only allow asynchronous service calls these classes  also expose events that are used by the application to know when a authentication request has completed. This is also the reason why there is no constructor creating and authenticating a user. Instead the default constructor for SilverlightPrincipal will simply create an anonymous unauthenticated user with no roles assigned. To authenticate a user I added a Validate method to the SilverlightPrincipal class that will call the internal Validate method on the SilverlightIdentity class which will invoke the service call to authenticate the user. SilverlightPrincipal also subscribes to a custom event on the SilverlightIdentity class to be notified when the authentication request is completed. If the user is authenticated the SilverlightPrincipal class will then invoke a service call to retrieve the roles for the user. When the role service call is complete it will fire an event to notify the caller of the Validate method that the request is complete. This event is also fired if the user failed authentication.

Once these classes were created I exposed a read-only property of type SilverlightPrincipal in the App class called CurrentPrincipal so that the principal would be available globally. In the Page class I also created a CurrentPrincipal property that references the principal object in the App class. This was more for convenience. Here is the property in the page class.

   1:  /// <summary>
   2:  /// Provides a shortcut to the current application principal.
   3:  /// </summary>
   4:  public SilverlightPrincipal CurrentPrincipal
   5:  {
   6:      get { return (Application.Current as App).CurrentPrincipal; }
   7:  }
 

Here is a sample on using the SilverlightPrincipal class to authenticate a user.

   1:  //Set up Principal Event Handlers
   2:  CurrentPrincipal.PrincipalValidationRequestCompleted += CurrentPrincipal_PrincipalValidationRequestCompleted;
   3:   
   4:  //Authenticate User
   5:  CurrentPrincipal.Validate(userName, password);

When the event handler is called it can then update the UI based on the current principal. Here is an example.

   1:  // Enables/Disables buttons based on the current application principal.
   2:  LogInManager.IsEnabled = !CurrentPrincipal.Identity.IsAuthenticated;
   3:  LogInEmployee.IsEnabled = !CurrentPrincipal.Identity.IsAuthenticated;
   4:  LogOut.IsEnabled = CurrentPrincipal.Identity.IsAuthenticated;
   5:   
   6:  ManagerOnlyTask.IsEnabled = CurrentPrincipal.IsInRole("Management");
   7:  EmployeeOnlyTask.IsEnabled = CurrentPrincipal.IsInRole("Employee");

There is also a corresponding LogOut method in the SilverlightPrincipal class that will invoke a log out service call and then reset the identity back to an anonymous unauthenticated identity with no roles assigned. It also has an event that can be subscribed to so the UI can be updated.

posted @ Thursday, May 22, 2008 7:21 AM | Feedback (1) |

Powered by: