身份验证、角色和配置文件

在想要验证用户的凭据、限制对某些操作的访问,或为您客户端项目中的各个用户保留属性时,您需要向您的 WCF RIA Services 解决方案添加身份验证域服务。在传统的 ASP.NET Web 应用程序中,您可以使用 ASP.NET 成员资格框架来执行这些功能。RIA Services 基于 ASP.NET 成员资格框架构建,因为它可以通过身份验证域服务向丰富 Internet 客户端公开成员资格框架。在添加身份验证域服务后,您可以启用下列功能:

  • 身份验证 - 验证用户的凭据,并将该用户标记为已登录或已注销。

  • 角色 - 按职责对用户分组,并向组中已通过身份验证的成员授予资源权限。

  • 配置文件 - 为已通过身份验证的用户保留属性,并在您的应用程序中检索这些属性。

本主题介绍如何使用 RIA Services 解决方案中的身份验证、角色和配置文件。

身份验证域服务

RIA Services 提供了“身份验证域服务”模板,以加快对表示层中的身份验证、角色和配置文件的访问。若要创建身份验证域服务,您只需在服务器项目中创建新项,并在创建该项时选择“身份验证域服务”模板。

RIA_ServicesAddAuth

添加身份验证域服务时,RIA Services 框架自动向该服务器项目添加两个类。表示身份验证服务的类派生自 AuthenticationBase 类。表示用户的类派生自 UserBase 类。该用户类包含已通过身份验证的用户的配置文件属性。

生成解决方案时,RIA Services 在客户端项目中自动生成一个 WebContext 类。WebContext 类支持您访问该身份验证域服务以及您客户端项目中的用户。需要使用 Current 属性检索 WebContext 的当前实例。WebContext 类派生自 WebContextBase

有关如何向 RIA Services 解决方案添加身份验证域服务的示例,请参见演练:将身份验证服务用于 Silverlight 导航应用程序

Silverlight 业务应用程序和身份验证

在选择使用“Silverlight 业务应用程序”模板创建解决方案时,解决方案会自动包括身份验证域服务和用来管理登录和注册用户的控件。默认情况下,该解决方案使用 Forms 身份验证,但您可以轻松地将其配置为使用 Windows 身份验证。角色已被启用并且定义了一个配置文件属性。有关默认包含在 Silverlight 业务应用程序中的身份验证功能以及如何将配置从 Forms 身份验证更改为 Windows 身份验证的示例,请参见演练:使用“Silverlight 业务应用程序”模板。有关基于 Silverlight 业务应用程序的默认功能进行构建的示例,请参见演练:将身份验证服务用于 Silverlight 业务应用程序

下图显示了注册窗口,这是 Silverlight 业务应用程序中包括的默认功能之一。

“注册”对话框

身份验证

RIA Services 提供的类可支持您在解决方案中轻松实现 Forms 身份验证或 Windows 身份验证。若要在您的 RIA Services 解决方案中使用身份验证,必须为服务器项目和客户端项目配置身份验证。有关更多信息,请参见如何:在 RIA Services 中启用身份验证

配置服务器和客户端项目后,通过调用 WebContext 对象上的 Login 方法,可从您的 Silverlight 应用程序以异步方式支持用户登录。使用 Windows 身份验证或检索具有持久化凭据的用户时,您不必调用 Login 方法。应改为调用 LoadUser 方法来检索通过 Windows 身份验证进行身份验证的用户,或者加载具有持久化凭据的用户。

在实现了身份验证之后,通常在客户端项目中使用下面的方法和属性。

成员 要使用的代码 任务

Authentication

WebContext.Current.Authentication

访问身份验证服务。

User

WebContext.Current.User

访问包含用户状态的对象。

Login

- 或 -

Login

- 或 -

Login

WebContext.Current.Authentication.Login(string, string)

- 或 -

WebContext.Current.Authentication.Login(LoginParameters)

- 或 -

WebContext.Current.Authentication.Login(LoginParameters, LoginOperation, object)

异步验证用户的凭据。

Logout

- 或 -

Logout

WebContext.Current.Authentication.Logout(boolean)

- 或 -

WebContext.Current.Authentication.Logout(LogoutOperation, object)

异步注销已通过身份验证的用户。

LoadUser

- 或 -

LoadUser

WebContext.Current.Authentication.LoadUser()

- 或 -

WebContext.Current.Authentication.LoadUser(LoadUserOperation, object)

加载已通过身份验证的用户、刷新用户状态、加载持久化的用户身份验证,或在使用 Windows 身份验证时检索主体用户对象。

下面的示例演示如何从登录按钮的事件处理程序调用 Login 方法。包含一个回调方法来响应登录操作的结果。

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;
}

角色

在实现身份验证后,您可以配置您的解决方案使用角色。可通过角色将用户分配到组中。然后,您可以指定特定的域操作仅供该角色的成员使用。您可以通过将 RequiresRoleAttribute 应用于域操作,限制对域操作的访问权限。有关更多信息,请参见如何:启用 RIA Services 中的角色

在实现了角色之后,通常使用下面的方法和属性。

成员 要使用的代码 任务

Roles

WebContext.Current.User.Roles

访问用户分配到的角色。

IsInRole

WebContext.Current.User.IsInRole(string)

确定通过身份验证的用户是否为指定角色的成员。

下面的示例演示了一个域操作,只有名为 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;
}

如果您在用户不具有必需凭据的情况下调用某一域操作,则该域操作将返回异常。您可以通过在调用域操作之前对凭据进行检查,避免这一情况发生。下面的示例演示如何在加载数据之前检查用户是否是必需角色的成员。

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;
    }
}

配置文件

配置文件属性支持您保存有关用户的信息。您可以使用这些属性为每个用户自定义您的应用程序。若要在您的解决方案中使用配置文件,您必须配置您的解决方案使用配置文件。有关更多信息,请参见如何:在 RIA Services 中启用配置文件

在实现了配置文件之后,通常使用下面的方法和属性。

成员 要使用的代码 任务

User

WebContext.Current.User

访问包含已添加到 User 类的所有属性的对象;例如 User.PhoneNumber

LoadUser

- 或 -

LoadUser

WebContext.Current.Authentication.LoadUser()

- 或 -

WebContext.Current.Authentication.LoadUser(LoadUserOperation, object)

刷新用户的状态。

SaveUser

- 或 -

SaveUser

WebContext.Current.Authentication.SaveUser(boolean)

- 或 -

WebContext.Current.Authentication.SaveUser(SaveUserOperation, object)

保存用户状态中的任何更改;例如在设置配置文件属性值之后。

下面的示例演示如何基于用户选定的值设置用户属性。

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;
}

处理客户端上的身份验证错误

您可以处理在登录、注销、加载或保存用户时出现的错误,方法是在调用这些方法时提供一个作为参数的回调方法。在该回调方法中,您可以添加代码以处理错误,并调用 MarkErrorAsHandled 方法以指定框架不会引发异常。使用 AuthenticationService 类,您可以在调用以下方法时提供回调方法:

  • LoadUser

  • Login

  • Logout

  • SaveUser

前面的“身份验证”一节中的示例说明了用于处理 Login 操作错误的回调方法。

有关更多信息,请参见客户端上的错误处理

限制对域服务的访问

实现身份验证和角色之后,您可以将域服务的访问权限限定给特定的用户。需要对整个域服务或该服务上的各个操作应用以下特性。对整个服务应用某个特性时,该特性将应用于所有操作。

  • RequiresAuthenticationAttribute - 指定只有具有有效身份验证凭据的用户才能访问该操作。

  • RequiresRoleAttribute - 指定只有属于指定角色的已通过身份验证的用户才能访问该操作。

还可以自行创建自定义的授权特性。有关更多信息,请参见如何:创建自定义授权属性

下面的示例演示具有三个域操作的域服务。RequiresAuthenticationAttributeRequiresRoleAttribute 特性用于限制访问权限。GetProducts 域操作可用于任何用户,GetSalesOrderHeaders 可用于经过身份验证的用户,GetCustomers 仅可用于 Managers 角色中的用户。

<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;
    }
}

另请参见

任务

演练:将身份验证服务用于 Silverlight 导航应用程序
演练:将身份验证服务用于 Silverlight 业务应用程序

概念

WCF RIA Services 的安全性