我在类似游戏的系统上工作。用户可以提交.class和.java文件以进行自定义行为。一些对象通过回调传递给用户,但如果用户可以自己构建这些对象(使用自定义参数),则对他来说意味着一个优势。我将禁止用户反思并密封我的包裹。如果我放弃所有的包结构(并使构造函数包私有),我可以得到这个工作,但我不想这样做。
以下是一个例子:
sscce.mycode.a.SomeClass.java :
package sscce.mycode.a;
import sscce.mycode.b.RestrictedObject;
import sscce.usercode.SomeUserClass;
public class SomeClass {
public static void main(String[] args) {
SomeUserClass userClass=new SomeUserClass();
// If I can create it from here, anyone can...
RestrictedObject object=new RestrictedObject();
userClass.someMethod(object);
}
}
sscce.mycode.b.Interface.java :
package sscce.mycode.b;
public interface Interface {
public void someMethod(RestrictedObject restrictedObject);
}
sscce.mycode.b.RestrictedObject.java :
package sscce.mycode.b;
public class RestrictedObject {
public RestrictedObject() {}
}
sscce.usercode.SomeUserClass.java :
package sscce.usercode;
import sscce.mycode.b.Interface;
import sscce.mycode.b.RestrictedObject;
public class SomeUserClass implements Interface {
@Override
public void someMethod(RestrictedObject restrictedObject) {
// It receives an instance, but cannot create it.
System.out.println("Got "+restrictedObject);
}
}
动机:将所有内容放在一个包中听起来很麻烦......
有没有人有关于如何在不展平包装的情况下实现这一目标的想法? 提前感谢任何解决方案,想法或评论,直到
答案 0 :(得分:1)
你可以通过以下方式实现,但是你应该仔细考虑是否真的想要使用这种方法,因为它非常缓慢而且非常坦率地说是不好的做法。 无论如何,无论如何可以这样做,我都会提出来:
public final class Secured {
private static final Set<Class<?>> allowedCallers = new HashSet<>();
static {
allowedCallers.add(Allowed.class);
}
private static final class SecurityManagerExtension extends SecurityManager {
private static final int OFFSET = 4;
@Override
protected Class<?>[] getClassContext() {
return super.getClassContext();
}
private Class<?> getCaller() {
try {
return getClassContext()[OFFSET];
} catch (ArrayIndexOutOfBoundsException e) {
return null;
}
}
}
private Secured() {
// protect against reflection attack
Class<?> caller = new SecurityManagerExtension().getCaller();
if (!this.getClass().equals(caller)) {
throw new IllegalStateException();
}
System.out.println("Secured instance constructed!");
}
public static Secured createInstance() {
// this gets the class name of the calling class
Class<?> caller = new SecurityManagerExtension().getCaller();
if (allowedCallers.contains(caller)) {
System.out.println("Created instance by '" + caller + "'!");
return new Secured();
} else {
System.out.println("No instance created because call was made by '" + caller + "'!");
return null;
}
}
}
注意类上的final关键字以防止子类化。如果您需要自己创建类的子类,请将final关键字移动到工厂方法。 另请注意,这不受序列化攻击的保护。