Spring Security 中的 Spring Expression Language (SpEL) 比较对象使用 equals() 还是 ==?
Posted
技术标签:
【中文标题】Spring Security 中的 Spring Expression Language (SpEL) 比较对象使用 equals() 还是 ==?【英文标题】:Spring Expression Language (SpEL) in Spring Security to compare object use equals() or ==? 【发布时间】:2013-10-27 16:38:51 【问题描述】:例如(方法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(),而在第二种情况下不调用?
//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);
【问题讨论】:
如果您要比较的类型是对象,我相信 SpEl 使用 .equals 进行比较。你总是可以做一个简单的测试,并在你正在使用 SpEl 比较的对象的 .equals 方法中放置一个断点 惊喜!不调用equals()! 我一般不会比较我的预授权标签中的对象,我认为在需要的地方调用 .equals 是可以接受的 【参考方案1】:根据 spEL 文档,您需要创建 ExpressionParser
实例,创建 Expression
实例并获取如下值
String name = "Nikola Tesla";
Expression exp = parser.parseExpression("name == 'Nikola Tesla'");
boolean result = exp.getValue(Boolean.class);
结果评估为“真”。也就是说,当我们需要比较任何两个对象时,我们需要重写 equals()
方法并将这两个对象传递给 parser#parseExpression("obj1 == obj2") ,然后调用 exp#getValue(Boolean.class)
进行评估。类似地,Expression 实例也可以有包含Obj1.equals(Obj2)
的表达式字符串,用于检查相等性。因此,两种检查相等性的方法都可以使用 spEL。
【讨论】:
表达式中可以使用任何 Spring-EL 功能,因此您还可以访问参数的属性。您是否编译了调试信息? 我在想SPEL执行构造'=='调用等于()【参考方案2】:rdm,我认为您必须使用权限评估器来评估表达式。我认为您并没有真正为以下表达式中的对象注入/传递值。
@Override
@PreAuthorize(" #one == #two ")
public String testEqualsInAnnotation(TestObject one, TestObject two)
//...
我尝试做同样的事情,但我未能传递值,因此无法评估表达式。我的建议是为上述表达式实现您的自定义权限评估器,并从评估器注入/传递值。概括我的想法,我的怀疑是对象是空的,这就是你无法评估它的原因。如果您真的可以在这里传递对象的值,请告诉我们:@PreAuthorize(" #one == #two ")
Added:
我正在使用权限评估器来评估 @PreAuthorize(...) 注释下的表达式。因为我无法像上面解释的那样将值传递给参数。如果可以传递/注入值,则最好降低使用权限评估器可能带来的复杂性。
rdm 或其他人,如果可能的话,你能告诉我如何传递 @PreAuthorize(...) 下的参数值吗?
很抱歉在 rdm 的帖子上提出另一个问题,提前感谢您的帮助!。
【讨论】:
我不明白你的问题) 首先,一、二对象不为空,我也不使用自定义权限评估器 好的,我收到了你对我另一篇文章的评论。这正是我的问题所在。我将在该帖子上添加更多解释,希望您检查一下。谢谢rdm!。【参考方案3】:您可能已经发现了这一点,因为它在原始帖子的“更新 2”中的 OpEq
代码中,但是...
比较运算符lt < gt > le <= ge >= eq == ne !=
基于java的Comparable
接口。
因此,如果您有一个自定义类型,希望能够在 SpEL 表达式中使用 ==
或 !=
进行比较,那么您可以编写它来实现 Comparable
。
当然,当它们不相等时,你必须找出一些合理的规则来决定哪个对象在另一个之前。
也就是说,我在 Spring 的当前文档中找不到任何表明这一点的内容。
【讨论】:
是比较需要以上是关于Spring Security 中的 Spring Expression Language (SpEL) 比较对象使用 equals() 还是 ==?的主要内容,如果未能解决你的问题,请参考以下文章
spring-security-oauth2中的HttpSecurity配置问题
如何使用 Spring Security 管理 Spring Boot 中的会话?
spring-security-oauth中的JdbcApprovalStore(ApprovalStore)有啥用?
Spring Security系列教程解决Spring Security环境中的跨域问题