您的位置:首页 > 其它

WCF RIA 服务 (三十五)-- 身份验证、角色、个性化 6

2013-07-11 15:52 537 查看
演练:在Silverlight Business应用程序中使用身份验证服务

Silverlight Business应用程序模板创建的解决方案自动允许身份验证(验证模式为Forms),角色和个性化功能。解决方案包含了数据表格来登录已经存在的用户和注册新用户。我们不用写额外的代码就可以使用这些特性。我们也可以通过定义角色、个性化属性来自定义解决方案。

在本演练中,我们将学习如何在Silverlight Business应用程序中使用身份验证、角色和个性化功能。我们将根据用户的凭证来限制对某些域操作的访问,并根据用户的偏好来定制用户界面。我们将使用ASP.NET网站管理工具来管理角色和用户。

创建网站、用户、角色

我们可以使用Silverlight Business应用程序模板提供的特性,来快速实施验证功能。在下面的章节,我们使用ASP.NET配置工具来创建用户和角色,并登陆此用户。我们还通过Silverlight Business应用程序提供的注册表格来注册新用户。

1. 在Visual Studio中,选择"文件->新建->项目"."新建项目"对话框打开。

2. 选择Silverlight项目类型。

3. 选择Silverlight Business Application模板,并命名为ExampleBusinessApplication.





4. 点击"OK".注意创建的项目结构。这个SL客户端项目中在Views文件夹中包含了SL页面。这些页面允许登陆用户和注册新用户。

5. 打开ASP.NET 网站管理工具。(首先,在资源管理器中,选择服务端项目,然后打开ASP.NET配置工具。

6. 在项目菜单中,选择ASP.NET Configuration.如果在项目菜单中,看不到ASP.NET Configuration选项,有可能是选择了客户端项目。





7.在ASP.NET网站管理工具中选择"安全"标签。





8. 在"角色"的部分,点击"创建或管理角色"链接。

9. 添加一个名为Managers的角色,并点击"添加角色"按钮。





10. 在右下角,点击"返回"按钮。

11. 在“用户"的部分,点击"创建用户"按钮。

12. 使用下面的值来创建新用户,并选择Managers角色复选框。

- User Name : CustomerManager

- Password : P@ssword

- E-mail : someone@example.com

- Security Question : Favorite color?

- Security Answer : Blue

- Managers role : selected





13. 点击"创建用户"按钮。

14. 关闭ASP.NET网站管理工具。

15. 运行解决方案。应用程序的首页将会显示在web浏览器中。

16. 在页面的右上角,点击”登陆"链接。登陆窗口将会出现。

17. 为用户名称输入CustomerManager,为密码输入p@ssword,并点击"OK"按钮。





现在我们就登陆这个用户了,注意到在页面右上角出现文本"Welcome CustomerManager"。

18. 点击"登出"按钮。这时我们就不再以CustomerManager登陆了。

下面的步骤,我们通过注册表格创建一个新用户。

19. 再次点击"登陆"链接。

20. 在登陆对话框中,点击"现在就注册"链接。注册表格就会出现了。

21. 用下面的信息填充注册表。

Username: SalesUser

Friendly name: SalesUser

Email: someone@example.com

Password: P@ssword

Security Question: What was the color of your first car?

Security Answer: Green





22. 点击"OK",创建一个新用户。注意,我们现在已经作为SalesUser登陆了。

23. 关闭浏览器。

24. 打开ASP.NET网站管理工具,点击"安全"标签。注意到已经有了两个用户和角色,即使我们只创建了一个角色。

25. 点击“创建或管理角色”,注意到Managers和Registered Users角色。Registered User角色是Business应用程序模板自动生成的。





26. 对"Registered Users",点击"管理"链接。注意,通过应用程序添加的名为SalesUser的用户已经在Registered Users角色中了。

27. 关闭ASP.NET网站管理工具。

定义访问权限和个性化属性

我们通过为域服务应用RequiresAuthenticationAttribute和RequiresRoleAttribute属性,来限制对域服务的访问。如果域操作 没有属性,对所有用户有效。在域操作上添加属性,并不能阻止用户调用域操作。只是没有所需凭证的用户会收到一个异常。

根据角色限制显示数 据

1. 在资源管理器中,在服务端项目中,点击App_Data文件夹,选择"添加->已存在项"。

2. 在"添加已存在项"对话框中,添加AdventureWorksLT示例数据库。

3. 在服务端,添加一个新项,并选择ADO.NET Entity Data Model模板。

4. 命名模型为AdventureWorksModel.edmx,并点击"添加"."实体数据模型向导"将会出现。

5. 选择"从数据库生成"选项,并点击"下一步".

6. 选择AdventureWorksLT数据库,并点击"下一步"。

7. 从数据库对象列表中,选择Customer,Product,以及SalesOrderHeader表,然后点击"完成"。实体数据模型将会出现在设计器 中。

8. 生成解决方案。

9. 在服务端,添加一个新项,并选择Domain Service Class模板。

10. 命名为AdventureWorksDomainService,然后点击"添加"。

11. 在"添加新域服务类"对话框中,选择Customer,Product和SalesOrderHeader实体。





12. 点击"OK"以完成创建域服务。

13. 在AdventureWorksDomainService类中,对GetSalesOrderHeader方法添加RequiresAuthenticationAttribute属性。

//添加访问权限
[RequiresAuthentication()]
public IQueryable<Employees> GetEmployees()
{
return this.ObjectContext.Employees;
}

14. 对GetCustomers方法添加RequiresRoleAttribute属性,并设置所需的角色为"Managers"。

//添加角色权限Managers
[RequiresRole("Managers")]
public IQueryable<Customers> GetCustomers()
{
return this.ObjectContext.Customers;
}

GetProducts方法对所有用户都可用,GetSalesOrderHeader只对验证用户可用,GetCustomers方法只对属于Managers角色的用户可 用。

[EnableClientAccess()]
public class DataDomainService : LinqToEntitiesDomainService<NorthWind_ENEntities>
{

// TODO:
// Consider constraining the results of your query method.  If you need additional input you can
// add parameters to this method or create additional query methods with different names.
// To support paging you will need to add ordering to the 'Customers' query.
//添加角色权限Managers
[RequiresRole("Managers")]
public IQueryable<Customers> GetCustomers()
{
return this.ObjectContext.Customers;
}

// TODO:
// Consider constraining the results of your query method.  If you need additional input you can
// add parameters to this method or create additional query methods with different names.
// To support paging you will need to add ordering to the 'Employees' query.
//添加访问权限
[RequiresAuthentication()]
public IQueryable<Employees> GetEmployees()
{
return this.ObjectContext.Employees;
}

// TODO:
// Consider constraining the results of your query method.  If you need additional input you can
// add parameters to this method or create additional query methods with different names.
// To support paging you will need to add ordering to the 'Products' query.

public IQueryable<Products> GetProducts()
{
return this.ObjectContext.Products;
}
}


下 面我们在Web.config文件中定义个性法属性。当我们把属性添加到服务端的用户类时,将会为客户端项目生成对应的属性。

1. 在服务端项目,打开Web.config文件。

2. 在元素内,添加名为DefaultRows的个性化属性。这个属性将保持 用户对显示的数据数量的偏爱。

<properties>
<add name="FriendlyName" />

<!--添加自定义属性-->
<add type="System.Int32" defaultValue="10" name="DefaultRows"/>

</properties>


3. 保存Web.config文件。

4. 在服务端项目中,展开Models文件夹。

5. 打开User.cs或User.vb文件,添加名为DefaultRows属性。

public partial class User : UserBase
{
//// NOTE: Profile properties can be added for use in Silverlight application.
//// To enable profiles, edit the appropriate section of web.config file.
////
//// public string MyProfileProperty { get; set; }

/// <summary>
/// Gets and sets the friendly name of the user.
/// </summary>
public string FriendlyName { get; set; }

//添加对应Web.config里增加的DefaultRows属性
public int DefaultRows { set; get; }
}


从 客户端使用身份验证服务

在调用有限制权限的域操作时,我们应该对用户检查所需的凭证。否则,将会抛出一个异常。在下面的部分, 我们将检查用户的凭证,并根据用户的凭证来填充一个到三个DataGrid控件。我们会根据用户个性化中的属性来得到显示的记录数量。对没有验证的用户, 默认的值是10。这部分没有让用户更改DefaultRows个性化属性的方式,不过在以后的部分会添加这个方式。

添加一个Silverlight页面来显示数据

1. 在客户端,在Views文件夹中添加新项。

2. 选择Silverlight Page模板,并命名为Reports.xaml。

3. 打开MainPage.xaml文件,并名为Link2的超链接按钮下面添加一个指向Reports页面的链接。

<HyperlinkButton x:Name="Link3" Style="{StaticResource LinkStyle}"
NavigateUri="/Reports" TargetName="ContentFrame" Content="{Binding Path=Strings.ReportsPageTile,Source={StaticResource ApplicationResources}}"/>


4. 在Assets/Resources文件夹内,打开ApplicationString.resx文件。

5. 添加一个新的名为ReportsPageTitle的字符串资源,并设置值为Reports。





6. 保存并关闭ApplicationString.resx文件。

7. 打开Reports.xaml文件,并添加如下XAML到Grid元素内。

<ScrollViewer x:Name="PageScrollViewer">
<StackPanel x:Name="ContentStackPanel">
<TextBlock x:Name="HeaderText"
Text="{Binding Path=Strings.ReportsPageTile,Source={StaticResource ApplicationResources}}"/>
<TextBlock x:Name="ContentText" Text="Display reports based on user permissions"/>

<sdk:DataGrid  x:Name="ProductsGrid" Margin="5"/>
<sdk:DataGrid x:Name="EmployeesGrid" Margin="5"/>
<sdk:DataGrid x:Name="CustomersGrid" Margin="5"/>

</StackPanel>
</ScrollViewer>

8. 拖拽三个DataGrid控件到名为ContentStackPanel的stack面板内。当我们从工具栏中拖拽DataGrid控件时,会在项目中添 加一个对System.Windows.Controls.Data程序集的应用,并在页面内添加System.Windows.Controls命名空 间。

9. 命名DataGrid控件为ProductsGrid、SalesOrdersGrid、CustomerGrid。

10. 对每个DataGrid控件,设置Margin为5.

11. 打开Reports.xaml.cs或Reports.xaml.vb。

12. 对c#,用using添加System.Windows.Ria,System.Windows.Ria.ApplicationServices,ExampleBusinessApplication.Web,和ExampleBusinessApplication.Resources命名空间。

13. 创建AdventureWorksDomainService的名为context的实例,并创建一个名为numberOfRows的变量来保存检索的记 录数量。

private DataDomainContext _dataDomainContext = new DataDomainContext();
int numberOfRows = 10;

14. 添加一个名为LoadRestrictedReports的方法,这个方法调用GetSalesOrderHeaderQuery方法和GetCustomerQuery方法。如果用户属于Managers角色,就显示对应的带结果的数据表格。

如果没有所需凭证的用户调用一个域操 作时,域操作会返回一个异常。我们可以通过在调用域操作之前检查凭证来避免这种情况。

private void LoadRestrictedReports()
{
LoadOperation<Employees> loadEmployees = _dataDomainContext.Load(_dataDomainContext.GetEmployeesQuery().Take(numberOfRows));
EmployeesGrid.ItemsSource = loadEmployees.Entities;
EmployeesGrid.Visibility = System.Windows.Visibility.Visible;
if (WebContext.Current.User.IsInRole("Managers"))
{
LoadOperation<Customers> loadCustomers = _dataDomainContext.Load(_dataDomainContext.GetCustomersQuery().Take(numberOfRows));
CustomersGrid.ItemsSource = loadCustomers.Entities;
CustomersGrid.Visibility = System.Windows.Visibility.Visible;
}
else
{
CustomersGrid.Visibility = System.Windows.Visibility.Collapsed;
}
}

15. 添加名为LoadReports的方法来检测是否用户已验证,如果已验证,就调用LoadRestricteReports方法。它还检索名为DefaultRows的个性化属性,并对User对象的PropertyChanged事件添加事件处理程序。最后,对所有用户调用GetProductsQuery方法。

private void LoadReports()
{
if (WebContext.Current.User.IsAuthenticated)
{
numberOfRows = WebContext.Current.User.DefaultRows; //WebConfig里添加的DefaultRows属性
WebContext.Current.User.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(User_PropertyChanged);
LoadRestrictedReports();
}
else
{
CustomersGrid.Visibility = Visibility.Collapsed;
EmployeesGrid.Visibility = Visibility.Collapsed;
}
LoadOperation<Products> loadProducts = _dataDomainContext.Load(_dataDomainContext.GetProductsQuery().Take(numberOfRows));
ProductsGrid.ItemsSource = loadProducts.Entities;
}

16. 对PropertyChanged事件添加事件处理程序,保证在DefaultRows属性改变时调用LoadReports方法。

void User_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "DefaultRows")
{
LoadReports();
}
}

17. 为LoggedIn和LoggedOut事件添加事件处理方法,并根据用户凭证的状况装载或隐藏数据。

void Authentication_LoggedIn(object sender, AuthenticationEventArgs e)
{
LoadReports();
}

void Authentication_LoggedOut(object sender, AuthenticationEventArgs e)
{
CustomersGrid.Visibility = Visibility.Collapsed;
EmployeesGrid.Visibility = Visibility.Collapsed;
}

18. 在构造函数内添加下面的代码:

public Reports()
{
InitializeComponent();

this.Title = ApplicationStrings.ReportsPageTile;
WebContext.Current.Authentication.LoggedIn+=new EventHandler<AuthenticationEventArgs>(Authentication_LoggedIn);
WebContext.Current.Authentication.LoggedOut+=new EventHandler<AuthenticationEventArgs>(Authentication_LoggedOut);
LoadReports();
}

以下是完整代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Navigation;
using ExampleBusinessApplication35.Web;
using System.ServiceModel.DomainServices.Client;
using System.ServiceModel.DomainServices.Client.ApplicationServices;

namespace ExampleBusinessApplication35.Views
{
public partial class Reports : Page
{
public Reports()
{
InitializeComponent();

this.Title = ApplicationStrings.ReportsPageTile;
WebContext.Current.Authentication.LoggedIn+=new EventHandler<AuthenticationEventArgs>(Authentication_LoggedIn);
WebContext.Current.Authentication.LoggedOut+=new EventHandler<AuthenticationEventArgs>(Authentication_LoggedOut);
LoadReports();
}

// Executes when the user navigates to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}

private DataDomainContext _dataDomainContext = new DataDomainContext();
int numberOfRows = 10;

private void LoadRestrictedReports()
{
LoadOperation<Employees> loadEmployees = _dataDomainContext.Load(_dataDomainContext.GetEmployeesQuery().Take(numberOfRows));
EmployeesGrid.ItemsSource = loadEmployees.Entities;
EmployeesGrid.Visibility = System.Windows.Visibility.Visible;
if (WebContext.Current.User.IsInRole("Managers"))
{
LoadOperation<Customers> loadCustomers = _dataDomainContext.Load(_dataDomainContext.GetCustomersQuery().Take(numberOfRows));
CustomersGrid.ItemsSource = loadCustomers.Entities;
CustomersGrid.Visibility = System.Windows.Visibility.Visible;
}
else
{
CustomersGrid.Visibility = System.Windows.Visibility.Collapsed;
}
}

private void LoadReports()
{
if (WebContext.Current.User.IsAuthenticated)
{
numberOfRows = WebContext.Current.User.DefaultRows; //WebConfig里添加的DefaultRows属性
WebContext.Current.User.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(User_PropertyChanged);
LoadRestrictedReports();
}
else
{
CustomersGrid.Visibility = Visibility.Collapsed;
EmployeesGrid.Visibility = Visibility.Collapsed;
}
LoadOperation<Products> loadProducts = _dataDomainContext.Load(_dataDomainContext.GetProductsQuery().Take(numberOfRows));
ProductsGrid.ItemsSource = loadProducts.Entities;
}

void User_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "DefaultRows")
{
LoadReports();
}
}

void Authentication_LoggedIn(object sender, AuthenticationEventArgs e)
{
LoadReports();
}

void Authentication_LoggedOut(object sender, AuthenticationEventArgs e)
{
CustomersGrid.Visibility = Visibility.Collapsed;
EmployeesGrid.Visibility = Visibility.Collapsed;
}
}
}

19. 运行解决方案。

20. 点击Reports链接。注意到,当我们没登陆时,只有产品表显示在报告页面。

21. 点击"登陆"链接,并以SalesUser登陆。会发现,产品和销售订单表显示出来。





22. 登出并以CustomerManager登陆。会发现,三个表都显示了。

23. 关闭web浏览器。

添加一个窗口来设置个性化属性

我们可以通过添加一个子窗口来允许用户编 辑DefaultRows个性属性。当值改变后,我们调用SaveUser方法来把值保存到数据源。我们通过当前WebContext实例的User对象 上的属性来检索当前的值。

1. 在客户端,在Views文件夹中添加新项。

2. 选择Silverlight Child Window模板,并命名为ProfileWindow.xaml。





3. 点击"添加"按钮。

4. 在ProfileWindow.xaml文件内,在Grid.RowDefinitions元素后添加XAML,来添加一个下拉列表选择要在报表中显示的 行数。

<StackPanel Orientation="Horizontal" Grid.Row="0">
<TextBlock Text="Number Of Rows to Display For Reports:"></TextBlock>
<ComboBox x:Name="defaultRows" Height="20" VerticalAlignment="Top">
<ComboBoxItem Content="1"></ComboBoxItem>
<ComboBoxItem Content="2"></ComboBoxItem>
<ComboBoxItem Content="3"></ComboBoxItem>
<ComboBoxItem Content="4"></ComboBoxItem>
<ComboBoxItem Content="5"></ComboBoxItem>
<ComboBoxItem Content="6"></ComboBoxItem>
<ComboBoxItem Content="7"></ComboBoxItem>
<ComboBoxItem Content="8"></ComboBoxItem>
<ComboBoxItem Content="9"></ComboBoxItem>
<ComboBoxItem Content="10"></ComboBoxItem>
<ComboBoxItem Content="15"></ComboBoxItem>
<ComboBoxItem Content="20"></ComboBoxItem>
</ComboBox>
</StackPanel>


5. 设置ChildWindow的Title属性为Select References。

6. 在ProfileWindow.xaml.cs中,添加下面的代码来检索和设置个性化属性

public ProfileWindow()
{
InitializeComponent();
string userDefaultRows = WebContext.Current.User.DefaultRows.ToString();
foreach (ComboBoxItem cbi in defaultRows.Items)
{
if (cbi.Content.ToString() == userDefaultRows)
{
defaultRows.SelectedItem = cbi;
break;
}
}
}

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

private void CancelButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = false;
}


7. 如果是VB,添加Imports命令引用System.Windows.Controls和System.Windows命名空间。

8. 展开Views/Login文件夹,并打开LoginStatus.xaml文件。

9. 添加一个指向profile文件的设置链接,在Logout按钮前添加下面的XAML

<StackPanel>
<Button x:Name="SettingsButton" Click="SettingsButton_Click" Content="Settings"
Margin="5"></Button>
<TextBlock Text=" | "></TextBlock>
</StackPanel>

10. 在LoginStatus.xaml.cs文件内,为设置链接添加点击事件处理方法。

private void SettingsButton_Click(object sender, RoutedEventArgs e)
{
ProfileWindow settingsWindow = new ProfileWindow();
settingsWindow.Show();
}


11. 运行解决方案。

12. 以CustomerManager或SalesUser登陆,注意到在登陆状态栏,现在包含一个"设置"的链接。





13. 点击"设置"链接,并设置默认的报表显示行数。





14. 打开报表页面,会注意到DataGrid现在包含我们所选的行数。

源代码: http://download.csdn.net/detail/eric_k1m/5754929
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: