Подтвердить что ты не робот

Как найти объект, называемый методом в Java

Можно ли найти объект, который вызвал метод в Java? У меня есть социальная сеть с группами и людьми. Если человек хочет покинуть группу, только тот, кто может удалить себя из группы, никто не может удалить этого человека, так или иначе человек, который вызвал метод, должен подтвердить его личность.

4b9b3361

Ответ 1

Проверка вызывающих абонентов метода - довольно распространенный запрос от неопытных программистов. Я удивлен, что он больше не появляется на SO. Но это действительно невероятно плохая идея (просто проверьте модель безопасности Java 2 (и, возможно, еще хуже)).

Есть несколько обстоятельств, когда важно реализовать это ограничение. Как говорит Оли Чарльверт, просто не делай этого. Но предположим, что это важно, но мы не собираемся проводить проверку стека.

Предположим, что мы доверяем группе. Рабочий, но бессмысленный подход - передать группе объект, стоящий за человека, которого может создать только человек. (Примечание. Ограничения на доступ к языку на 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));
    }
 }

Другой подход заключается в создании "общедоступной" версии Person, которая может быть подвержена другим.

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 опущено для "краткости".)

Ответ 2

Вы можете сделать это с отражением, проанализировав трассировку стека (как описано в этом вопросе: Как найти вызывающего метода с использованием stacktrace или reflection?).

Однако в большинстве ситуаций это было бы злоупотреблением размышлениями. Вы должны серьезно подумать о том, чтобы ваш метод принял дополнительный аргумент caller (который должен заполнить вызывающий объект this).

Ответ 3

Риск с решением Oli заключается в том, что вредоносный код может вызвать метод remove и указать другой объект-вызывающий объект.

Если вы используете инфраструктуру безопасности, например Spring Security, вы можете запросить текущего принципала и разрешить удаление этого пользователя из группы, или если этот пользователь является администратором, разрешить удаление любого пользователя из группа.