Authentication, Roles, and Profiles
[WCF RIA Services Version 1 Service Pack 2 is compatible with either .NET framework 4 or .NET Framework 4.5, and with either Silverlight 4 or Silverlight 5.]
You add the authentication domain service to your WCF RIA Services solution when you want to verify a user's credentials, restrict access for certain operations, or retain properties for each user from your client project. In a traditional ASP.NET Web application, you can use the ASP.NET Membership framework to perform these functions. RIA Services builds upon the ASP.NET Membership framework by exposing the Membership framework to rich Internet clients through the authentication domain service. After adding an authentication domain service, you can enable the following functions:
Authentication - to verify a user's credentials and mark the user as logged in or logged out.
Roles - to group users by responsibilities and grant resource permissions to authenticated members of a group.
Profiles - to retain properties for authenticated users and retrieve those properties in your application.
This topic introduces how you use authentication, roles, and profiles in a RIA Services solution.
Authentication Domain Service
RIA Services provides the Authentication Domain Service template to facilitate accessing authentication, roles, and profiles on the presentation tier. To create an authentication domain service, you simply create a new item in the server project and select the Authentication Domain Service template when creating the item.
When you add an authentication domain service, the RIA Services framework automatically adds two classes to the server project. The class that represents the authentication service derives from the AuthenticationBase<T> class. The class that represents the user derives from the UserBase class. The user class contains the profile properties for an authenticated user.
When you build the solution, RIA Services automatically generates a WebContext class in the client project. The WebContext class enables you to access the authentication domain service and the user in your client project. You use the Current property to retrieve the current instance of the WebContext. The WebContext class derives from WebContextBase.
For an example of how to add an authentication domain service to a RIA Services solution, see Walkthrough: Using Authentication Service with Silverlight Navigation Application.
Silverlight Business Application and Authentication
When you select the Silverlight Business Application template to create a solution, the solution automatically includes an authentication domain service and controls to manage logging in and registering users. By default, the solution uses Forms authentication, but you can easily configure it for Windows authentication. Roles are enabled and one profile property is defined. For an example of the authentication features that are included by default in a Silverlight Business Application and how you change the configuration from Forms authentication to Windows authentication, see Walkthrough: Using the Silverlight Business Application Template. For an example of building upon the default features in a Silverlight Business Application, see Walkthrough: Using Authentication Service with Silverlight Business Application.
The following illustration shows the registration window, which is one of the default features included in the Silverlight Business Application.
Authentication
RIA Services provides classes that enable you to easily implement Forms authentication or Windows authentication in your solution. To use authentication in your RIA Services solution, you must configure the server project and the client project for authentication. For more information, see How to: Enable Authentication in RIA Services.
After configuring the server and client projects, you asynchronously log in users from your Silverlight application by calling the Login method on the WebContext object. When using Windows authentication or when retrieving a user with persisted credentials, you do not have to call the Login method. Instead, you call the LoadUser method to retrieve the user that is authenticated through Windows authentication or to load a user with persisted credentials.
The following methods and properties are typically used in the client project when you have implemented authentication.
Member |
Code to use |
Task |
---|---|---|
WebContext.Current.Authentication |
To access the authentication service. |
|
WebContext.Current.User |
To access the object that contains the state of the user. |
|
-or- -or- |
WebContext.Current.Authentication.Login(string, string) -or- WebContext.Current.Authentication.Login(LoginParameters) -or- WebContext.Current.Authentication.Login(LoginParameters, LoginOperation, object) |
To asynchronously verify the user's credentials. |
-or- |
WebContext.Current.Authentication.Logout(boolean) -or- WebContext.Current.Authentication.Logout(LogoutOperation, object) |
To asynchronously log out an authenticated user. |
-or- |
WebContext.Current.Authentication.LoadUser() -or- WebContext.Current.Authentication.LoadUser(LoadUserOperation, object) |
To load an authenticated user, refresh user state, load persisted user authentication, or retrieve principal user object when used with Windows authentication. |
The following example shows how to call the Login method from an event handler for a login button. A callback method is included to respond to the results of the login operation.
Private Sub LoginButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim lp As LoginParameters = New LoginParameters(UserName.Text, Password.Password)
WebContext.Current.Authentication.Login(lp, AddressOf Me.LoginOperation_Completed, Nothing)
LoginButton.IsEnabled = False
LoginResult.Text = ""
End Sub
Private Sub LoginOperation_Completed(ByVal lo As LoginOperation)
If (lo.HasError) Then
LoginResult.Text = lo.Error.Message
LoginResult.Visibility = System.Windows.Visibility.Visible
lo.MarkErrorAsHandled()
ElseIf (lo.LoginSuccess = False) Then
LoginResult.Text = "Login failed. Please check user name and password."
LoginResult.Visibility = System.Windows.Visibility.Visible
ElseIf (lo.LoginSuccess = True) Then
SetControlVisibility(True)
End If
LoginButton.IsEnabled = True
End Sub
private void LoginButton_Click(object sender, RoutedEventArgs e)
{
LoginParameters lp = new LoginParameters(UserName.Text, Password.Password);
WebContext.Current.Authentication.Login(lp, this.LoginOperation_Completed, null);
LoginButton.IsEnabled = false;
LoginResult.Text = "";
}
private void LoginOperation_Completed(LoginOperation lo)
{
if (lo.HasError)
{
LoginResult.Text = lo.Error.Message;
LoginResult.Visibility = System.Windows.Visibility.Visible;
lo.MarkErrorAsHandled();
}
else if (lo.LoginSuccess == false)
{
LoginResult.Text = "Login failed. Please check user name and password.";
LoginResult.Visibility = System.Windows.Visibility.Visible;
}
else if (lo.LoginSuccess == true)
{
SetControlVisibility(true);
}
LoginButton.IsEnabled = true;
}
Roles
After you have implemented authentication, you can configure your solution to use roles. With roles, you can assign users to groups. Then, you can specify that a particular domain operation is only available to members of that role. You restrict access to a domain operation by applying the RequiresRoleAttribute to the domain operation. For more information, see How to: Enable Roles in RIA Services.
The following methods and properties are typically used when you have implemented roles.
Member |
Code to use |
Task |
---|---|---|
WebContext.Current.User.Roles |
To access the roles the user is assigned to. |
|
WebContext.Current.User.IsInRole(string) |
To determine whether the authenticated user is a member of a specified role. |
The following example shows a domain operation with access restricted to members of a role named Managers.
<RequiresRole("Managers")> _
Public Function GetCustomers() As IQueryable(Of Customer)
Return Me.ObjectContext.Customers
End Function
[RequiresRole("Managers")]
public IQueryable<Customer> GetCustomers()
{
return this.ObjectContext.Customers;
}
If you call a domain operation when the user does not have the required credentials, the domain operation returns an exception. You can avoid this situation by checking the credentials before calling the domain operation. The following example shows how to check if the user is a member of the required role before loading the data.
Private Sub LoadRestrictedReports()
Dim loadSales = context.Load(context.GetSalesOrderHeadersQuery().Take(numberOfRows))
SalesOrdersGrid.ItemsSource = loadSales.Entities
SalesOrdersGrid.Visibility = System.Windows.Visibility.Visible
If (WebContext.Current.User.IsInRole("Managers")) Then
Dim loadCustomers = context.Load(context.GetCustomersQuery().Take(numberOfRows))
CustomersGrid.ItemsSource = loadCustomers.Entities
CustomersGrid.Visibility = System.Windows.Visibility.Visible
Else
CustomersGrid.Visibility = System.Windows.Visibility.Collapsed
End If
End Sub
private void LoadRestrictedReports()
{
LoadOperation<SalesOrderHeader> loadSales = context.Load(context.GetSalesOrderHeadersQuery().Take(numberOfRows));
SalesOrdersGrid.ItemsSource = loadSales.Entities;
SalesOrdersGrid.Visibility = System.Windows.Visibility.Visible;
if (WebContext.Current.User.IsInRole("Managers"))
{
LoadOperation<Customer> loadCustomers = context.Load(context.GetCustomersQuery().Take(numberOfRows));
CustomersGrid.ItemsSource = loadCustomers.Entities;
CustomersGrid.Visibility = System.Windows.Visibility.Visible;
}
else
{
CustomersGrid.Visibility = System.Windows.Visibility.Collapsed;
}
}
Profiles
Profile properties enable you to save information about the user. You can use these properties to customize your application for each user. To use profiles in your solution, you must configure your solution for profiles. For more information, see How to: Enable Profiles in RIA Services.
The following methods and properties are typically used when you have implemented profiles.
Member |
Code to use |
Task |
---|---|---|
WebContext.Current.User |
To access the object that contains all of the properties that you have added to the User class; for example, User.PhoneNumber. |
|
-or- |
WebContext.Current.Authentication.LoadUser() -or- WebContext.Current.Authentication.LoadUser(LoadUserOperation, object) |
To refresh the state of the user. |
-or- |
WebContext.Current.Authentication.SaveUser(boolean) -or- WebContext.Current.Authentication.SaveUser(SaveUserOperation, object) |
To save any changes in the user state; such as, after setting a profile property value. |
The following example shows how to set a user property based on the value selected by the user.
Private Sub OKButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) Handles OKButton.Click
Dim newSelection = Integer.Parse(defaultRows.SelectionBoxItem.ToString())
If (newSelection <> WebContext.Current.User.DefaultRows) Then
WebContext.Current.User.DefaultRows = newSelection
WebContext.Current.Authentication.SaveUser(True)
End If
Me.DialogResult = True
End Sub
private void OKButton_Click(object sender, RoutedEventArgs e)
{
int newSelection = int.Parse(defaultRows.SelectionBoxItem.ToString());
if (newSelection != WebContext.Current.User.DefaultRows)
{
WebContext.Current.User.DefaultRows = newSelection;
WebContext.Current.Authentication.SaveUser(true);
}
this.DialogResult = true;
}
Handling Authentication Errors on the Client
You can handle errors that arise when logging in, logging out, loading, or saving users by providing a callback method as a parameter when you call those methods. In the callback method, you add code to handle the error and call the MarkErrorAsHandled method to specify that the framework will not throw an exception. The AuthenticationService class enables you to provide a callback method when you call the following methods:
The example in the previous "Authentication" section shows a callback method for the Login operation that handles errors.
For more information, see Error Handling on the Client.
Restricting Access to a Domain Service
After you have implemented authentication and roles, you can restrict access on a domain service to only particular users. You apply the following attributes to either the entire domain service or to individual operations on the service. When you apply an attribute to the entire service, it applies to all of the operations.
RequiresAuthenticationAttribute - Specifies that only users with valid authentication credentials can access the operation.
RequiresRoleAttribute - Specifies that only authenticated users who belong to the specified roles can access the operation.
You can also create your own customized authorization attribute. For more information, see How to: Create a Custom Authorization Attribute.
The following example shows a domain service with three domain operations. The RequiresAuthenticationAttribute and RequiresRoleAttribute attributes are used to restrict access. The GetProducts domain operation is available to any user, GetSalesOrderHeaders is available to authenticated users, and GetCustomers is available to only users in the Managers role.
<EnableClientAccess()> _
Public Class AdventureWorksDomainService
Inherits LinqToEntitiesDomainService(Of AdventureWorksLT_DataEntities)
<RequiresRole("Managers")> _
Public Function GetCustomers() As IQueryable(Of Customer)
Return Me.ObjectContext.Customers
End Function
Public Function GetProducts() As IQueryable(Of Product)
Return Me.ObjectContext.Products
End Function
<RequiresAuthentication()> _
Public Function GetSalesOrderHeaders() As IQueryable(Of SalesOrderHeader)
Return Me.ObjectContext.SalesOrderHeaders
End Function
End Class
[EnableClientAccess()]
public class AdventureWorksDomainService : LinqToEntitiesDomainService<AdventureWorksLT_DataEntities>
{
[RequiresRole("Managers")]
public IQueryable<Customer> GetCustomers()
{
return this.ObjectContext.Customers;
}
public IQueryable<Product> GetProducts()
{
return this.ObjectContext.Products;
}
[RequiresAuthentication()]
public IQueryable<SalesOrderHeader> GetSalesOrderHeaders()
{
return this.ObjectContext.SalesOrderHeaders;
}
}
See Also
Tasks
Walkthrough: Using Authentication Service with Silverlight Navigation Application
Walkthrough: Using Authentication Service with Silverlight Business Application