如何:创建自定义授权属性

本主题演示如何添加自定义属性以进行授权。WCF RIA Services 框架提供了 RequiresAuthenticationAttributeRequiresRoleAttribute 属性。使用这些属性,您能够轻松指定哪些域操作仅对已通过身份验证的用户或具有特定角色的用户可用。除了这两个属性外,您可以创建表示自定义授权逻辑的属性,然后将该属性应用到域操作。

公开域服务时,域服务对网络上的所有用户都可用。不能假定您的客户端应用程序是将访问域服务的唯一应用程序。可以使用自定义身份验证属性来限制对域操作的访问,甚至在您的客户端应用程序之外访问域操作时也是如此。

在本主题中,您通过创建从 AuthorizationAttribute 派生的类并重写 IsAuthorized 方法以提供自定义逻辑,创建了一个自定义授权属性。您可以使用 IPrincipal 参数和 AuthorizationContext 参数来访问您的自定义身份验证代码中可能需要的信息。AuthorizationContext 对象对于查询操作为 null

创建自定义授权属性

  1. 在服务器项目中,创建从 AuthorizationAttribute 派生的类。

  2. 重写 IsAuthorized 方法并添加用于确定授权的逻辑。

    下面的示例显示一个名为 RestrictAccessToAssignedManagers 的自定义属性,该属性检查已通过身份验证的用户是否是正在更改其 EmployeePayHistory 记录的员工的经理:

    Public Class RestrictAccessToAssignedManagers
        Inherits AuthorizationAttribute
    
        Protected Overrides Function IsAuthorized(ByVal principal As System.Security.Principal.IPrincipal, ByVal authorizationContext As System.ComponentModel.DataAnnotations.AuthorizationContext) As System.ComponentModel.DataAnnotations.AuthorizationResult
            Dim eph As EmployeePayHistory
            Dim selectedEmployee As Employee
            Dim authenticatedUser As Employee
    
            eph = CType(authorizationContext.Instance, EmployeePayHistory)
    
            Using context As New AdventureWorksEntities()
                selectedEmployee = context.Employees.SingleOrDefault(Function(e) e.EmployeeID = eph.EmployeeID)
                authenticatedUser = context.Employees.SingleOrDefault(Function(e) e.LoginID = principal.Identity.Name)
            End Using
    
            If (selectedEmployee.ManagerID = authenticatedUser.EmployeeID) Then
                Return AuthorizationResult.Allowed
            Else
                Return New AuthorizationResult("Only the authenticated manager for the employee can add a new record.")
            End If
        End Function
    End Class
    
    public class RestrictAccessToAssignedManagers : AuthorizationAttribute
    {
        protected override AuthorizationResult IsAuthorized(System.Security.Principal.IPrincipal principal, AuthorizationContext authorizationContext)
        {
            EmployeePayHistory eph = (EmployeePayHistory)authorizationContext.Instance;
            Employee selectedEmployee;
            Employee authenticatedUser;
    
            using (AdventureWorksEntities context = new AdventureWorksEntities())
            {
                selectedEmployee = context.Employees.SingleOrDefault(e => e.EmployeeID == eph.EmployeeID);
                authenticatedUser = context.Employees.SingleOrDefault(e => e.LoginID == principal.Identity.Name);
            }
    
            if (selectedEmployee.ManagerID == authenticatedUser.EmployeeID)
            {
                return AuthorizationResult.Allowed;
            }
            else
            {
                return new AuthorizationResult("Only the authenticated manager for the employee can add a new record.");
            }
        }
    }
    
  3. 若要执行自定义授权逻辑,请将自定义授权属性应用到域操作。

    下面的示例显示已应用到域操作的 RestrictAccessToAssignedManagers 属性:

    <RestrictAccessToAssignedManagers()> _
    Public Sub InsertEmployeePayHistory(ByVal employeePayHistory As EmployeePayHistory)
        If ((employeePayHistory.EntityState = EntityState.Detached) _
                    = False) Then
            Me.ObjectContext.ObjectStateManager.ChangeObjectState(employeePayHistory, EntityState.Added)
        Else
            Me.ObjectContext.EmployeePayHistories.AddObject(employeePayHistory)
        End If
    End Sub
    
    [RestrictAccessToAssignedManagers]
    public void InsertEmployeePayHistory(EmployeePayHistory employeePayHistory)
    {
        if ((employeePayHistory.EntityState != EntityState.Detached))
        {
            this.ObjectContext.ObjectStateManager.ChangeObjectState(employeePayHistory, EntityState.Added);
        }
        else
        {
            this.ObjectContext.EmployeePayHistories.AddObject(employeePayHistory);
        }
    }