The data we work with in business application is valuable. We need to protect the data.. sometimes by keeping up with exactly who accesses and updates what data when and other times we need to actively prevent data from being accessed expected by trust parties.
The web is increasingly becoming a personal place – applications often “know about you” enabling users to having customized settings that work everywhere the apps works.
In this example, I will take our ever popular SuperEmployees application and augment it to show more details on the authentication and personalization.
You can see the full series here.
The demo requires (all 100% free and always free):
Let’s start by looking at how we ensure that only authenticated users can access access the data and keep a very simple log of who access the data.
Starting with the original example, let’s look at adding authentication to the GetSuperEmployees() method on the DomainService in the server project.
Once we use the RequiresAuthentication attribute, the system will ensure that only calls from authenticated users make it through. That means we can do some very simple such as logging who is accessing the data and when:
(check out a package such as Log4net for a complete solution for logging).
Now when we run the application, no results are returned.
We need to log in to see some results… Luckily the Business Application Template that ships with .NET RIA Services includes great support for this.
Click on login
Notice here, we could change to use window auth to get integrated NTLM security, either way works fine.
Then register now
and we can create a new user directly from the Silverlight client.
Notice if you want to customize the look and feel of any of these dialogs, it is easy to do by looking in the Views\LoginControl.xaml, Views\LoginWindow.xaml.
And if you want to control the backend on how these are implemented, you can by looking in server project under Services\AuthenticationService.cs and UserRegistrationService.cs. By default these go against the ASP.NET Membership and roles system, but you can customize them to do whatever you’d like by simply overriding the methods there.
Now, we just need to react to the logged in event. In this case, I am going to simply reload the data when the user logs in. Lines 10-13 signs up for the logged in event and sets reloads the data, this time, as an authenticated user.
And notice, the client knows who I am:
And the server knows as well.. If you go look at the log file we create in the DomainService we will see:
So, that is cool, but I think we can do a bit better on the client user experience. After all, I get no error whatsoever to tell me I need to log in to see the data.
First, let’s follow best practice and handle the DDS.LoadedData event and simply show any errors that are returned.
Then the implementation is very simple:
Now, when we run this app, we get this error:
That is helpful, maybe for a developer, but for an end user, maybe we want something more explicit.
The first step is to not even make the request if the user is not authenticated. We know that on the client, so this is very easy to do.
First, let’s sign up for the DDS.DataLoading event to capture the load before it happens.
then we will simple cancel the load if the user is not authenticated.
Now, let’s provide an alternate way to tell the user they need to log on. We simply add some text and make it visible only when the user is not authenticated.
The implementation of the value convert is pretty simple.
Now, when we run this, we get a nice UX:
Then when we log in, it looks nice.
We can even make it a bit better by giving users an easy to to log in from here:
What we showed in this section is how easy it is to require authentication for data and how to create a great user experience for this on the client.
Now that we have the basics of authentication down, let’s see how we can provide a bit more of a personalized experience. For many applications, uses spend a huge amount of time in the application, we want them to feel comfortable and in control of their experience. For the first part of this, let’s create a user setting for the background color of the application. Each user can have a different value and it should follow them no mater what machine they run the application on.
Let’s start be defining a profile property in the web.config file.
Then we can make this strongly typed by adding it to the AuthenticationService.cs file on the server.
Now we can simply access this on the client. First let’s define a page to set this value. in MyFirstPage.xaml… let’s add some UI:
We can handle the save button click as follows..
Notice in lines 3-4 we are normalizing the string name of the color so that it is “xaml compliant”..
Then in line 5 we are setting the strongly typed User.PageBackgroundColor property.
Then in lines 6-9 we are simply giving some UI hints as we save this value back to the server.
Of course this will only work if the user is logged in first, so this time, let’s be proactice and encourage the user to log in when they hit the page for the first time.
The last step here is the honor this value when it is set. That turns out to be pretty easy in this case. Just go to MainPage.Xaml and databind the LayoutRoot’s backgroun color to this value.
then when we log in…
And if we change the color to blue…
And notice the color change effects the whole app.
And if I hit the app from a different machine, on a different browser, my setting still carries forward… We start off not logged in we get the default:
but when we log in… our settings show up.
Now this is a user specific setting, so if I create a new user “Glenn” and set his background color to pink
that doesn’t effect the background color for Darb…
OK, background color is fun and all, but what might be even more useful is to store some state on how I last left the application. This ensures that as I access the application from over time, the context of my work is preserved.
So, let’s add a few more fields to our profile..
then update the User class to make this strongly typed.
We need to set the UI based on the user’s settings.
And we need to call that when the page is navigated to…
and when the user logs on.
Next we need to store the values back to the server at the right time. This SaveUserState method plucks the right values out of the UI, and saves them the server if the values have changed.
We need to call this method when the user navigates away.
and, periodically we check to see if we need to save the changes back to the server. So we set this up in the forms constructor..
Now, when we run it.. setup some sort order and a filter
then log out
log back in (from a different machine) and we see it is back just where we left off.
What we saw in this section what how to personalize the user experience based on the user preferences.
In this last section, let’s look at how to build out an admin UI.. What we want to do is provide a page that allows Admins to see all the users and edit their profile settings.
First, let’s go into the AuthenticationService and add some custom methods to return all the users. We should be sure that only users in the Admin role can access this service.
Now, lets add some Silverlight UI to consume this. We will create a new page called “Admin”. The first thing we want to do is to prompt the user to log in if they are not already logged in as a user in the admin role.
Next, we define a DomainDataSource for accessing the AuthenticationService
then we define some simple UI for working with the data..
Now, we run it.. log in but it doesn’t give us any data… why?
Well, the user we created is not an Admin. To make them a Admin, go to the Web Admin tool and add them to the “Admin” role.
Then under Roles, Add a new role for “Admin”
and under Users, “Manager User”… here you can easily add your user to the role.
Now when I log on and go to the Admin page, I can access the all the user’s settings.
What we saw in this section was how to build an admin UI for your applications.