任务 2:对工作流服务启用基于声明的授权

在此任务中,要确保只有一组用户凭据可以对您在练习 1:创建基本工作流服务中创建的工作流服务调用操作。这些凭据以 ClaimSet 的形式传递到服务。有关 ClaimSet 的更多信息,请参见Managing Claims and Authorization with the Identity Model

提示

使用 Visual Studio 工作流设计器创建或管理工作流服务时,该设计器有时会产生虚假的验证错误。如果可以成功地生成项目,请忽略验证错误。

通过 ClaimSet 启用用户验证

  1. 如果当前没有打开 WorkflowServiceTutorial 解决方案,请打开 Visual Studio 2008,单击**“文件”,突出显示“打开”**,并导航到 WorkflowServiceTutorial 解决方案。

  2. 在**“解决方案资源管理器”窗格中的 WorkflowServiceTutorial 项目节点下,右击“引用”子文件夹,然后选择“添加引用”。或者,如果您创建了 Visual Basic 解决方案,请右击 WorkflowServiceTutorial 项目节点,然后选择“添加引用”**。

  3. 在**“添加引用”对话框中,在“NET”选项卡下选择“System.IdentityModel”,然后单击“确定”**。

  4. 此任务使用 ClaimSetList 对象,因此,请使用 Workflow1.cs 顶部的语句添加以下内容:

    using System.IdentityModel.Claims;
    using System.Collections.Generic;
    

    如果您创建了 Visual Basic 解决方案,请右击 WorkflowServiceTutorial 项目节点,然后选择**“属性”。选择“引用”选项卡,然后在“导入的命名空间”**下单击 System.IdentityModel.Claims 的复选框。System.Collections.Generic 命名空间已经受支持。

  5. 如果工作流服务的工作流设计器不可见,请右击 Workflow1.cs(如果您创建了 Visual Basic 解决方案,则右击 Workflow1.vb)打开该设计器,并选择**“视图设计器”**。

  6. 在 Workflow1InitialState StateActivity 活动中,双击 WaitToStartService EventDrivenActivity 活动以展开该复合活动。

  7. 突出显示与 StartupService 操作相关联的 ReceiveActivity 活动。

  8. 在**“属性”窗格中的“OperationValidation”**下,键入 ValidateUser 并按 Enter,以自动生成 OperationValidation 事件的事件处理程序。

  9. 导航到 ValidateUser 事件处理程序。

    在 ValidateUser 的正文中,验证服务以前是否已经识别了用户,如果未识别,则不要让他们调用任何操作。例如,如果销售雇员启动订单并且直到几天以后才返回完成它,则这非常有用。在让用户对服务调用任何其他操作之前,应该验证是否是同一用户。因为恶意用户可能会模仿对话和上下文 ID,所以不能使用对话和上下文 ID。

        Private Sub ValidateUser(ByVal sender As System.Object, ByVal e As System.Workflow.Activities.OperationValidationEventArgs)
            For Each claims As ClaimSet In e.ClaimSets
                ' Find the claim that contains the name of the operation caller.
                Dim opCaller As List(Of Claim) = claims.FindClaims(ClaimTypes.Name, Rights.PossessProperty).ToList()
    
                ' Retrieve the name of the caller from the claim.
                Dim opCallerName As String = opCaller(0).Resource.ToString()
    
                ' If this is the caller's first time through the ValidationUser method, set 
                ' the operation caller's name to a global variable named "owner." Every subsequent
                ' operation that uses this method will verify that the caller of
                ' the operation is the same as the caller of the initial operation before
                ' either validating or invalidating the caller.
                If [String].IsNullOrEmpty(owner) Then
                    owner = opCallerName
                ElseIf Not owner.Equals(opCallerName) Then
                    e.IsValid = False
                End If
            Next
        End Sub
    
    private void ValidateUser(object sender, OperationValidationEventArgs e)
    {
        foreach (ClaimSet claims in e.ClaimSets)
        {     
            // Find the claim that contains the name of the operation caller.
            List<Claim> opCaller = claims.FindClaims(ClaimTypes.Name, Rights.PossessProperty).ToList<Claim>();
    
            // Retrieve the name of the caller from the claim.
            string opCallerName = opCaller[0].Resource.ToString();
    
            // If this is the caller's first time through the ValidationUser method, set 
            // the operation caller's name to a global variable named "owner." Every subsequent
            // operation that uses this method will verify that the caller of
            // the operation is the same as the caller of the initial operation before
            // either validating or invalidating the caller.
            if(String.IsNullOrEmpty(owner))
            {
                owner = opCallerName;
            }
            else if (!owner.Equals(opCallerName))
            {
                e.IsValid = false;
            }
        }
    }
    
  10. 声明一个名为“owner”的变量以在接收后续操作调用时用于验证,如以下代码所示:

    Public class ServerWorkflow
        Inherits StateMachineWorkflowActivity
    
        ' These variables are bound to the input and output parameters of the ReceiveActivity.
        Public returnValue As Int32 = Nothing
        Public inputValue As Int32 = Nothing
    
        'This variable contains the user name for the NT account used in operation validation.
        Public owner As String = Nothing
    ...
    End Class
    
    public sealed partial class ServerWorkflow : StateMachineWorkflowActivity
    {
        public ServerWorkflow()
        {
            InitializeComponent();
        }
    
        // These variables are bound to the input and output parameters of the ReceiveActivity.
        public int returnValue = default(int);
        public int inputValue = default(int);
    
        // This variable contains the user name for the NT account used 
        // in operation validation.
        public string owner = default(string);
        ...
    }
    
  11. 对于其余每个操作,将 OperationValidation 事件与 ValidateUser 方法相关联。

  12. 生成您的解决方案并验证您的授权检查是否起作用。

    如果在设置 owner 变量后具有不同用户名的用户尝试对服务调用操作,则会将以下错误消息返回到客户端:

    Security check failed.
    

    提示

    ClaimSetPrincipalPermissionRolePrincipalPermissionName 之前得到处理,因此,如果您对 NT 帐户组执行两项不同的授权检查(一项使用 ClaimSet,另一项使用 PrincipalPermissionRole),则 ClaimSet 授权检查将首先进行。

另请参见

任务

任务 1:在工作流服务上启用基于角色的授权

其他资源

练习 2:针对工作流服务实现安全功能

版权所有 (C) 2007 Microsoft Corporation。保留所有权利。