4

Spring Security の Spring Expression Language (SpEL) でオブジェクトを比較するには、equals() または ==? を使用します。

例 (メソッド equals () は呼び出されません!):

class SecurityObject {      
   public boolean equals(Object obj) {
  //...
   }
 }

@PreAuthorize(" #secObject == #otherSecObject ") 
public void securityMethod(SecurityObject secObject, SecurityObject otherSecObject) {                        
   //...        
}

これは正常です!?どこでも @PreAuthorize(" #secObject.equals(#otherSecObject) ") を使用する必要がありますか?

アップデート

なぜ最初のケースで Spring Security が .equals() を呼び出し、2 番目のケースではそうでないのですか?

      //TestObject 

      public class TestObject {

      private static final Logger log = LoggerFactory.getLogger(TestObject.class);

      private Long id;

      public TestObject(Long id) {
           this.id = id;
      }

       @Override
       public int hashCode() {
           int hash = 7;
           hash = 71 * hash + Objects.hashCode(this.id);
           return hash;
       }

       @Override
       public boolean equals(Object obj) {

       log.info("equals");

       if (obj == null) {
          return false;
       }

       if (getClass() != obj.getClass()) {
         return false;
       }
       final TestObject other = (TestObject) obj;
       if (!Objects.equals(this.id, other.id)) {
         return false;
       }
      return true;
  }               
}

//TestService

@PreAuthorize(" #one == #two ")
public String testEqualsInAnnotation(Long one, Long two) {        
    //...
}

@Override
@PreAuthorize(" #one == #two ")
public String testEqualsInAnnotation(TestObject one, TestObject two) {
    //...
}

//Test

    log.info("for Long");
    Long one = new Long(500);
    Long two = new Long(500);        

    log.info("one == two: {}", (one==two)? true : false); // print false
    log.info("one equals two: {}", (one.equals(two))? true : false); // print true

    testService.testEqualsInAnnotation(one, two); //OK

    log.info("for TestObject");

    TestObject oneObj = new TestObject(new Long(500));
    TestObject twoObj = new TestObject(new Long(500));              

    log.info("oneObj == twoObj: {}", (oneObj==twoObj)? true : false); // print false
    log.info("oneObj equals twoObj: {}", (oneObj.equals(twoObj))? true : false); // print true

    testService.testEqualsInAnnotation(oneObj, twoObj); // AccessDeniedException: Access is denied

更新 2

equals() はまったく呼び出されませんでした

           package org.springframework.expression.spel.ast;

           import org.springframework.expression.EvaluationException;
           import org.springframework.expression.spel.ExpressionState;
           import org.springframework.expression.spel.support.BooleanTypedValue;

/**
 * Implements equality operator.
 *
 * @author Andy Clement
 * @since 3.0
 */
public class OpEQ extends Operator {

    public OpEQ(int pos, SpelNodeImpl... operands) {
        super("==", pos, operands);
    }

    @Override
    public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
        Object left = getLeftOperand().getValueInternal(state).getValue();
        Object right = getRightOperand().getValueInternal(state).getValue();
        if (left instanceof Number && right instanceof Number) {
            Number op1 = (Number) left;
            Number op2 = (Number) right;
            if (op1 instanceof Double || op2 instanceof Double) {
                return BooleanTypedValue.forValue(op1.doubleValue() == op2.doubleValue());
            } else if (op1 instanceof Long || op2 instanceof Long) {
                return BooleanTypedValue.forValue(op1.longValue() == op2.longValue());
            } else {
                return BooleanTypedValue.forValue(op1.intValue() == op2.intValue());
            }
        }
        if (left!=null && (left instanceof Comparable)) {
            return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) == 0);
        } else {
            return BooleanTypedValue.forValue(left==right);
        }
    }

}
4

3 に答える 3

2

OpEqこれは、元の投稿の「Update 2」のコードに含まれているため、すでに発見されているかもしれませんが...

比較演算子は、Java のインターフェースlt < gt > le <= ge >= eq == ne !=に基づいています。Comparable

==そのため、または!=SpEL 式で比較できるようにしたいカスタム型がある場合は、それを書いて実装することができますComparable。もちろん、それらが同等でない場合に、どちらのオブジェクトが他のオブジェクトよりも前にあるかを決定するための適切なルールを見つけ出す必要があります。

とはいえ、Spring の現在のドキュメントには、これを示すものは何も見つかりません。

于 2016-06-07T16:34:40.543 に答える
1

rdm、式を評価するにはパーミッション エバリュエーターを使用する必要があると思います。次の式のオブジェクトに実際に値を注入/渡したとは思いません。

@Override
@PreAuthorize(" #one == #two ")
public String testEqualsInAnnotation(TestObject one, TestObject two) {
    //...

同じことをしようとしましたが、値を渡すことができなかったため、式を評価できませんでした。私の提案は、上記の式のカスタム権限評価子を実装し、評価子から値を注入/渡すことです。私の考えを一般化するために、私の容疑者はオブジェクトがnullであるため、評価できなかったのです。ここで実際にオブジェクトの値を渡すことができるかどうかお知らせください:@PreAuthorize(" #one == #two ")

Added:

@PreAuthorize(...) アノテーションの下で式を評価するためにパーミッションエバリュエーターを使用しています。上記で説明したように、パラメーターに値を渡すことができなかったためです。値を渡したり注入したりできる場合は、パーミッション エバリュエーターを使用することで発生する可能性がある複雑さを軽減できます。

rdm など、可能であれば @PreAuthorize(...) の下のパラメーターの値を渡す方法を教えてもらえますか?

rdm の投稿で別の質問をして申し訳ありませんが、よろしくお願いします!.

于 2013-10-30T00:16:56.883 に答える