Java でメソッドを呼び出したオブジェクトを見つけることはできますか? 私はグループや個人とのソーシャル ネットワークを持っています。ある人がグループを離れたい場合、その人だけがグループから自分自身を削除できます。他の誰もその人を削除することはできません。何らかの方法でメソッドを呼び出した人がその身元を証明する必要があります。
3 に答える
メソッドの呼び出し元をチェックすることは、経験の浅いプログラマーからの非常に一般的な要求です。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));
}
}
もう 1 つのアプローチは、他の人に公開できる "パブリック" バージョンの 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
「簡潔さ」のために省略されています。)
スタック トレースを分析することにより、リフレクションを使用してこれを行うことができます(この質問で説明されているように: スタック トレースまたはリフレクションを使用してメソッドの呼び出し元を見つけるにはどうすればよいですか? )。
ただし、ほとんどの場合、これはリフレクションの乱用になります。メソッドが呼び出される追加の引数を取ることを強く検討する必要がありますcaller
(呼び出し元が を入力する必要がありthis
ます)。
Oli のソリューションのリスクは、悪意のあるコードが「削除」メソッドを呼び出して、別の呼び出し元オブジェクトを指定できることです。
Spring Security などのセキュリティ フレームワークを使用している場合は、現在のプリンシパルを要求して、グループからのそのユーザーの削除のみを許可するか、そのユーザーが管理者である場合は、グループからの任意のユーザーの削除を許可できます。