【问题标题】:Protect access to Java methods depending on custom conditions根据自定义条件保护对 Java 方法的访问
【发布时间】:2011-03-03 10:29:13
【问题描述】:

简而言之:我想根据特定条件允许/禁止执行 Java 方法。最好的解决方案/机制/技术是什么?

长问题,通过一个(诚然愚蠢的)示例:

假设我在车辆控制器中有几种方法,例如void openWindow(Window w)void openRoof()void keepSpeed(double speedKmh)。如果下雨,不应该调用openRoof,我们希望建立一个机制来确保它。类似地,如果速度低于 60 公里/小时,则禁止使用 keepSpeed,例如在下大雨时使用 openWindow,或者在高于时速时使用 100 km/h

由于访问雨量/速度传感器需要几行代码,而且这些条件无处不在,我不想在方法体中使用 use 断言或条件,但我宁愿让它们易于使用由域开发人员。此外,我希望将安全问题与打开窗口等的实际逻辑分开。更复杂的自定义条件也应该易于配置。

例如,我想要这个:

@ForbidIf('default:rain') openWindow();
@ForbidIf('default:speedBelow(60)') keepSpeed();
@ForbidIf('default:speedAbove(100)', 'custom:rainsALot') openWindow();

如果有帮助,这个应用程序是一个 Spring 驱动的客户端-服务器应用程序。

【问题讨论】:

    标签: java security spring aop


    【解决方案1】:

    您可以使用简单的 Spring AOP 方面,如下所示(未经测试):

    @Aspect
    public class SecurityAspect{
    
        @Pointcut("execution(@ForbidIf * *(*))")
        public void annotatedMethodCalled(){}
    
        @Before("annotatedMethodCalled() && @target(annotation) && target(bean)")
        public void beforeRestrictedMethodCall(
            final ForbidIf annotation, final Object bean){
            final Expression expression =
                new SpelExpressionParser().parseExpression(annotation.value());
            if(!Boolean.TRUE.equals(expression.getValue(bean))){
                throw new IllegalArgumentException();
            }
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      类似的东西在 Spring Security 中实现为expression based access control,但我认为它不适合你的情况。

      但是,通过创建一个可以针对特定上下文评估 SpEL expressions 的切面,应该很容易从头开始实现类似的功能。

      【讨论】:

      • 感谢您的建议。我还没有深入探索 Spring Security。为什么不适合?
      • @espinchi:如果您不需要身份验证等,我认为使用 Spring Security 将是矫枉过正。
      【解决方案3】:

      OP,评论 Andreas_D 的回答:“如果禁止执行,我希望引发运行时异常。在这种情况下,如果条件为 false,则意味着在当前情况下不应该调用此方法。 "

      有什么问题:

      public void openWindow() {
          if (itsRaining()) {
              throw new IllegalStateException("Window should not open if it's raining");
          }
      }
      

      ?我的意思是,做一个注释实际上是同样的事情,只是更复杂(特别是如果你的方法条件变得复杂,例如,如果下雨、下雪、车速 > 100 KPh、风速时不应打开窗户> 6,温度低于冰点等)。

      当然,我也可能错过了重点。只是想暗示过度思考、工程化或使问题复杂化并不是唯一的途径。当然,不想说使用 AOP 或注释是过度思考/工程化/复杂化的问题。这篇文章可能也是基于简化的示例。

      【讨论】:

      • 这是一个非常有道理的担忧。我不想使用这种前置条件样式有两个原因:这些条件需要多次调用我不想直接依赖的其他库;而且,它们不是明显的先决条件,它们会是“如果能量高于某个阈值,电源转换器不应该比这个速率更快地改变强度”,所以我宁愿把这个逻辑分开。跨度>
      【解决方案4】:

      这是一个有趣的想法,尽管我看到了一些实际问题。您可以注释一个方法并参考一些环境设置。但是如果禁止执行,应该怎么做呢?

      考虑这个例子:

       @ForbidIf('default:durationIs(0))') double getSpeed(double distance);
      

      并像使用它

       double speed = getSpeed(distance);   // the duration is set globally in this example
      

      如果持续时间值设置为 0 会发生什么 - 在这种情况下应该为速度分配什么?还是要引发运行时异常?

      在您的情况下,我们已经有两种方式来实现条件执行:

       // check before calling
       if (isSaveToOpenWindow())
         openWindow();
      

       public void openWindow() {
          if (!isSaveToOpenWindow())
            return;
      
          // open window
       }
      

      【讨论】:

      • 如果禁止执行,我希望引发运行时异常。在这种情况下,如果条件为假,则表示在当前情况下不应该调用此方法。
      【解决方案5】:

      这里需要 AOP 吗?装饰器模式可以简单得多,而且需要的魔法也少得多。只需将实现包装为:

      class ProtectedWindowOpener implements WindowOpener {
      
         WindowOpener delegate ...
      
          void openWindow(Window w) {
              if (!allowOpen(w)) {
                throw new PermissionDeniedException...
              }
              delegate.openWindow(w);
          }
      
          boolean allowOpen(Window w) {
            // security logic here
      
          }
      }
      

      这样既保持安全逻辑分离,又具有不将代码嵌入字符串的优点,这意味着eclipse可以做自己的事情。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-08-18
        • 2018-04-20
        • 2020-07-26
        • 2016-07-19
        • 2013-05-08
        • 2020-01-25
        • 2014-04-22
        • 1970-01-01
        相关资源
        最近更新 更多