问题 如何在Java中找到调用方法的对象


我可以在Java中找到调用方法的对象吗?我有一个团体和人的社交网络。如果一个人想要离开一个团体,只有那个人可以从团体中移除,没有其他人可以移除那个人,不管怎样,调用该方法的人必须证明它的身份。


3077
2018-03-11 00:42


起源

只需将'this'传递给方法,但除非您计划让其他人调用您的代码,否则我不明白为什么您担心安全问题。只是不要写任何允许A从C中删除B的代码,或者确实允许A获取对B的引用。 - user207421


答案:


检查方法的调用者是来自没有经验的程序员的相当普遍的请求。我很惊讶它在SO上看起来并不常见。但这是一个非常糟糕的想法(只需查看Java 2(可能更糟糕的是)安全模型)。

在很少的情况下,实施此限制很重要。正如Oli Charlesworth所说,只是不要这样做。但我们假设它很重要,但我们不打算进行堆栈检查。

让我们首先假设我们信任该团体。一种有效但荒谬的方法是向该群体传递一个对象,该对象只代表该人可以创建的人。 (注意Java语言访问限制是基于类的。不同的实例可以创建这样的支持,但代码必须在 Person 类。)

public final class Group { // Can't have a malicious subclass.
    public void deregisterPerson(Person.Standin standin) {
        Person person = standin.person();
        ...
    }
}
public class Person { // May be subclassed.
    public final class Standin { // Could be one per Person.
        private Standin() { // Hide constructor from other outer classes.
        }
        public Person person() {
            return Person.this;
        }
    }
    private void groupDeregister(Group group) {
        group.deregisterPerson(new Standin());
    }
 }

如果我们不信任该组,那么我们可以扩展替身以引用该组。这可以防止恶意组将某个人从其他组中取消注册。

public class Group { // Can have malicious subclasses.
    public void deregisterPerson(Person.GroupDeregister deregister) {
        if (deregister.group() != this) { // Not equals...
            throw new IllegalArgumentException();
        }
        Person person = deregister.person();
        ...
    }
}
public class Person { // May be subclassed.
    public final class GroupDeregister {
        private final Group group;
        private GroupDeregister(Group group) { // Hidden.
            this.group = group;
        }
        public Person person() {
            return Person.this;
        }
        public Group group() {
            return group;
        }
    }
    private void groupDeregister(Group group) {
        group.deregisterPerson(new GroupDeregister(group));
    }
 }

另一种方法是制作可以暴露给他人的“公开”版本的人。

public class Person { // "PrivatePerson"
    public PublicPerson publicPerson() {
         return new PublicPerson(this);
    }
    private void groupRegister(Group group) {
        group.registerPerson(this);
    }
    private void groupDeregister(Group group) {
        group.deregisterPerson(this);
    }
    ...
}
public class PublicPerson {
    private final Person person;
    public PublicPerson(Person person) {
        this.person = person;
    }
    @Override public final boolean equals(Object obj) {
        return obj instanceof Person && (Person)obj.person == person;
    }
    @Override public final int hashCode() {
        return person.hashCode();
    }
    ...methods, but no raw registration...
 }
 public class Group {
     private final Set<Person> members = new IdentityHashSet<>(); // No Object.equals.
     public void registerPerson(Person person) {
         members.add(person);
     }
     public void deregisterPerson(Person person) {
         members.remove(person);
     }
     public Set<PublicPerson> members() {
         // This will be more concise in Java SE 8.
         Set<PublicPerson> publics = new HashSet<>();
         for (Member member : members) {
             publics.add(member.publicPerson());
         }
         return unmodifiableSet(publics);
     }
}

Objects.requireNonNull 遗漏了“简洁”。)


8
2018-03-11 03:41





你可以这样做 反射 通过分析堆栈跟踪(如此问题中所述: 如何使用堆栈跟踪或反射找到方法的调用者?)。

但是,在大多数情况下,这将是滥用反思。您应该强烈考虑让您的方法采用额外的参数调用 caller (调用者应该填写 this)。


4
2018-03-11 00:44



是的,但是如果我想从我的朋友列表中删除朋友,我可以调用这样的方法:group.removeFriend(myFriend,myFriend //这是调用者)。只有该组的管理员才能删除成员。 - John Smith
@JohnSmith:当然。解决方案是:不要那样做! - Oliver Charlesworth
@JohnSmith:如果你真的担心那个场景,那就添加一个 protected final 辅助方法 Person (或者基类是什么),它负责正确调用 group.removeFriend方法。 - Oliver Charlesworth
该链接不相关:它找到调用者 类不是 目的。 - Navin
这将找不到调用对象的类。它将找到定义调用此方法的方法的类。如果您试图找到抽象类的具体实现,这不一定有帮助。 - dhasenan


Oli解决方案的风险在于恶意代码可以调用'remove'方法并指定不同的调用方对象。

如果您使用的是安全框架(如Spring Security),则可以请求当前主体并仅允许从该组中删除该用户,或者如果该用户是管理员,则允许从该组中删除任何用户。


0
2018-03-11 00:51



如果您允许执行任意代码,这只是一个问题。这听起来不是一个好主意...... - Oliver Charlesworth
你可以保证编写代码的一件事是,有一天别人会维护它,他们会做一些愚蠢的事情。 - Jason
当然,但那是 总是 真正。你无法防止任意愚蠢!虽然我同意设计API的原则,以致它很难错误地使用,但添加一个完整的安全机制只是为了防止某人假设将错误的参数传递给方法对我来说似乎有些过分。 - Oliver Charlesworth
我觉得从OP中假设用户必须登录到这个系统是安全的(为了至少识别自己)。要求是阻止用户删除其他用户。该解决方案可确保并减少错误的可能性。 - Jason