【问题标题】:Flowing WCF Role-Based Security through to UI将 WCF 基于角色的安全性传递到 UI
【发布时间】:2010-12-01 10:47:23
【问题描述】:

我正在寻找一些关于如何处理以下场景的最佳实践 - 将权限从 WCF 服务层传递到 UI:

我有 WCF 服务,其方法已用 PrincipalPermission 属性修饰。我想要一种方法让客户端在调用该方法之前检查他们是否具有所需的权限。

这方面的一个基本示例可能是检查用户是否可以执行特定功能(例如提交订单),然后可以使用该功能来启用/禁用 UI 中的按钮。

可能的选择是将bool CanSubmitOrder() 之类的“闲聊”操作添加到服务中,或者使用单个方法OrderServicePermissions GetPermissions() 返回带有属性CanSubmitOrder 的消息?然后我可以将“提交订单”按钮的启用状态设置为结果。

那么有人知道更好的方法,甚至是最佳实践吗?

提前致谢!

【问题讨论】:

    标签: wcf security user-interface role-based principalpermission


    【解决方案1】:

    有两种通用的类型来实现检查逻辑:

    1. 共享库。示例是“RIA 服务 + Silverlight”。

      优点:易于实现。

      缺点:没有互操作性(仅限 .NET);每次库更改都需要客户端更新。

    2. 在服务部分实现常用方法验证。 优点: 互操作性,如果检查逻辑发生变化,无需客户端更新

      缺点:可能很复杂,因为它只在你身上

    如果我们使用 SOA,最好使用第二选择,前提是您不是仅在您的公司中使用应用程序,而 .NET 无处不在。

    示例

    让我们考虑一个常见的例子。我们有一个 windows/wpf 表单。并且有两个字段:字符串类型的“姓”,int类型的“年龄”;和一个“保存”按钮。我们需要在客户端进行一些检查

    1) 对于某些用户,“保存”按钮被禁用;

    2) 姓氏不能为空,最大长度为256;

    3) 年龄不能小于0;

    调用保存的方法是

    void Save(string surname, int age);
    

    在服务中创建第二个方法,返回带有验证信息的 PermissonAnswerDTO 对象类型;

    PermissonAnswerDTO SaveValidate(string surname, int age);
    

    及主要验证方法

    // If arguments are wrong
            [FaultContract(typeof(NotSupportedException))]
            // If the user have permisson to invoke this method
            [FaultContract(typeof(CustomNotEnoughPermission))]
            PermissonAnswerDTO Validate(string methodName, object[] methodParams);
    

    验证。

    在加载窗口时调用 Validate("SaveValidate", null)。如果抛出 CustomNotEnoughPermission 类型的异常,那么我们会阻止“保存”按钮。

    如果用户可以保存,则调用用户数据Validate("SaveValidate", object[2]{"Surname", "-60"};。 -60 无效,因此我们得到 PermissonAnswerDTO 类型的答案对象,其中包含以下信息:

    ParameterName: "age",
    ExceptionMessage: "age cannot be less then null".
    

    我们可以优雅地向用户展示这些信息。


    我对此的看法是,微软总有一天会实现这一点,并像往常一样调用新技术。大多数情况下,微软的技术并没有宣传的那么具有革命性。例如 Windows Identity Foundation 和 Reactive Extensions。

    完整示例

    [DataContract]
        public class ParameterExceptionExplanaitonDTO
        {
            [DataMember]
            public string ParameterName;
            [DataMember]
            public string ExceptionMessage;
        }
    
    [DataContract]
    public class PermissonAnswerDTO
    {
        [DataMember]
        public bool IsValid;
    
        [DataMember]
        public ParameterExceptionExplanaitonDTO[] ParameterExceptions;
    }
    
    public class Service1 : WcfContracts.IService1
    {
        // If arguments are wrong
        [FaultContract(typeof(NotSupportedException))]
        // If the user have permisson to invoke this method
        [FaultContract(typeof(CustomNotEnoughPermission))]
        public PermissonAnswerDTO Validate(string methodName, object[] methodParams)
        {
            //1) Using Reflection find the method with name = <methodName + Validate>
            //2) Using Reflection cast each object in "object[] methodParams" to the required type
            //3) Invoke method
        }
    
        private PermissonAnswerDTO GetUserNameValidate(int id)
        {
            //logic to check param
        }
    
        public string GetUserName(int id) 
        {
            // if the user calls method we need validate parameter
            GetUserNameValidate(id);
    
            //some logic to retreive name
        }
    }
    

    【讨论】:

      【解决方案2】:

      好吧,如果您能够改进您的应用程序以使用 Windows Identity Foundation (WIF) 来保护您的服务,您可以使用 RequestSecurityTokenResponse 的 DisplayToken 属性来实现这一点。

      http://msdn.microsoft.com/en-us/library/microsoft.identitymodel.protocols.wstrust.requestsecuritytokenresponse.requesteddisplaytoken.aspx

      假设您的安全令牌服务支持它,显示令牌可能包含一个声明集,允许您将权限流入 UI,例如禁用绑定到用户无法调用的服务的控件。显示令牌是针对 CardSpace 实现的 WS-Trust 的扩展,因此它不太可能在 Windows 世界之外得到广泛支持。

      但请注意,有些人认为显示令牌是坏消息并且违反了身份第一定律:

      http://www.francisshanahan.com

      虽然其他人认为这是解决常见问题的合理而务实的方法:

      http://blogs.msdn.com/b/vbertocci/archive/2007/10/31/on-displaytoken.aspx

      【讨论】:

      • 我使用的是 ADSF,它似乎不支持 DisplayTokens。有没有类似的东西可以用来接收客户的索赔?
      • 是否可以让 ADFS 发布非加密令牌(即承载令牌)。这将不太安全,因为任何有权访问它的人都可以读取令牌内容,而不仅仅是依赖方,但至少您的客户端可以读取令牌内容......
      【解决方案3】:

      在您的服务调用中具有PrincipalPermission 属性的全部意义在于,您不必提前检查调用者是否有权调用 - 如果他没有,WCF 运行时将抛出一个例外。

      为什么不只依赖这个内置机制呢?为什么不将您的服务调用放在 try..catch 块中并在异常确实发生时处理它们?无论如何,这应该是“例外”的情况,对吧?

      除了你所描述的之外,我没有看到任何其他“神奇”的方式。但普遍接受的做法是调用并处理任何发生的异常。

      马克

      【讨论】:

      • 我认为这真的归结为 UI 和工作流程我猜 - 在某些情况下,提前知道用户可以做什么是有用的,而不会产生多次服务调用的额外成本和异常抛出/管理。一个示例是根据权限设置视图的默认状态。与其对各种方法进行多次调用、处理异常和设置状态,不如进行一次调用以获取详细信息,然后使用结果设置状态。
      • 我想我将使用 OrderServicePermissions GetPermissions() 路由,这将允许我在适当的情况下将 OrderServicePermissions 消息添加到其他服务调用结果中,以减少所需的调用次数。它的工作量实际上差不多,但它允许我将其全部打包到服务中,让我的客户尽可能地精简和简单。不过感谢您的 cmets...
      猜你喜欢
      • 2013-03-21
      • 2011-05-12
      • 1970-01-01
      • 2013-01-20
      • 2012-03-18
      • 2019-03-13
      • 1970-01-01
      • 1970-01-01
      • 2011-08-19
      相关资源
      最近更新 更多