根据自定义条件保护对 Java 方法的访问

发布于 2024-10-20 05:52:23 字数 776 浏览 1 评论 0 原文

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

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

假设我在车辆控制器中有几种方法,例如 void openWindow(Window w)void openRoof() void keepSpeed(double speedKmh)。如果下雨,则不应调用 openRoof,我们希望建立一种机制来确保这一点。同样,如果速度低于 60 公里/小时,则禁止 keepSpeed,就像如果下雨很多或速度高于 100 公里/小时,则禁止 openWindow

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

例如,我想要这个:

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

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

In short: I want to allow/forbid the execution of Java methods depending on certain conditions. What is the best available solution/mechanism/technique?

Long question, via an (admittedly dumb) example:

Say I have several methods in a vehicle controller, like void openWindow(Window w), void openRoof(), void keepSpeed(double speedKmh). If it rains, the openRoof should not be called, and we want to put in place a mechanism to ensure it. Similarly, if the speed is below 60 km/h, keepSpeed is forbidden, like openWindow if it rains a lot or if the speed if above 100 km/h.

Since accessing the rain/speed sensors requires several lines of code, and these conditions are used everywhere, I don't want to use use assertions or conditions in the body of the methods, but I'd rather make them easily used by domain developers. Besides, I'd like the security concern to be separated from the actual logic of opening the windows, etc. More complex, custom conditions should be easy to configure too.

For instance, I'd like to have this:

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

If it helps, this application is a Spring-powered client-server application.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

梦言归人 2024-10-27 05:52:23

您可以使用简单的 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();
        }
    }

}

You can use a simple Spring AOP aspect, something like this (untested):

@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();
        }
    }

}
那些过往 2024-10-27 05:52:23

Spring Security 中实现了类似的内容 基于表达式的访问控制,但我认为它不适合您的情况。

然而,通过创建一个可以评估 针对特定上下文的 SpEL 表达式

Something similar is implemented in Spring Security as expression based access control, but I think it's not suitable in your case.

However, it should be easy to implement similar functionality from scratch by creating an aspect that can evaluate SpEL expressions against a certain context.

小兔几 2024-10-27 05:52:23

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

有什么问题:

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

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

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

OP, commenting to Andreas_D's answer: "If the execution is forbidden, I want a runtime exception to be raised. In this case, if the condition is false, it means this method should have never been called under the current circumstances."

What's wrong with:

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

? I mean, doing an annotation is effectively the same thing, only more complex (especially if your conditions for the method grow in complexity, for example if the window should not be opened if it's raining, snowing, vehicle speed > 100 KPh, wind speed > 6, temperature below freezing, etc).

Of course, I could also just be missing the point. Just wanted to give the hint that overthinking, -engineering or -complicating the problem aren't the only paths to take. Don't want to say that using AOP or annotations are overthinking/engineering/complication a problem, of course. Probably basing this post on the simplified example, too.

千纸鹤 2024-10-27 05:52:23

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

考虑这个例子:

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

This is an interesting idea, although I see some real problems. You may annotate a method and refer to some environment settings. But if execution is forbidden, what should be done instead?

Consider this example:

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

and use it like

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

What should happen if the duration value is set to 0 - what should be assigned to speed in that case? Or do you want to raise a runtime exception?

In your case, we already have two ways to implement conditional execution:

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

and

 public void openWindow() {
    if (!isSaveToOpenWindow())
      return;

    // open window
 }
秋叶绚丽 2024-10-27 05:52:23

这里需要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 可以完成其业务。

Do you need AOP here? the Decorator pattern can be a lot simpler and requires a lot less magic. Just wrap the implementation with:

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

    }
}

Which keeps the security logic separate and also has the advantage of not embedding code in a string, which means eclipse can do its business.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文