我在我的REST接口上使用
Spring-data-rest,并且已经在暴露的端点上实现了自定义安全检查.一切正常,但现在我遇到了一些非平凡的情况,我想知道Spring数据是否能够解决这个问题.
我有以下型号:
@Entity
public class Cycle {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "unique_cycle_id")
private long id;
@Column(name = "user_id")
private long userId;
...
@OneToMany(cascade = CascadeType.ALL)
@JoinTable(name = "cycles_records", joinColumns = @JoinColumn(name = "unique_cycle_id"),
inverseJoinColumns = @JoinColumn(name = "unique_record_id"))
private List<Record> records;
}
@Entity
public class Record {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "unique_record_id")
private long id;
...
}
在获取一个循环时,我检查登录用户是否与我的Cycle实体中的userId具有相同的id.
我已经实现了这样的cystom安全检查:
@Slf4j
@Component
public class SecurityCheck {
public boolean check(Record record, Authentication authentication) {
log.debug("===Security check for record===");
if (record == null || record.getCycle() == null) {
return false;
}
return Long.toString(record.getCycle().getUserId()).equals(authentication.getName());
}
public boolean check(Cycle cycle, Authentication authentication) {
if (cycle == null) {
return false;
}
return Long.toString(cycle.getUserId()).equals(authentication.getName());
}
}
但是现在,我正在尝试对记录执行类似的安全检查.因此,在获取给定周期的记录时,我需要检查周期的userId是否与身份验证对象中的id匹配.
我的RecordRepository上有以下方法:
@Repository
public interface RecordRepository extends JpaRepository<Record, Long> {
@PreAuthorize("hasRole('ROLE_ADMIN') OR @securityCheck.check(???, authentication)")
Page<Record> findByCycle_Id(@Param("id") Long id, Pageable pageable);
}
是否可以使用我在此securityCheck中使用此方法查询的ID访问循环内的userId?如果没有,那么实现此功能的Spring方法是什么?
对不起,我的问题不明确.如果有必要进一步解释,请告诉我.
编辑:
我通过在后置过滤器中访问返回的页面找到了快速而又脏的解决方案.缺点是当返回的数组为空时我可以访问不属于我登录用户的记录(所以我仍然在寻找一些更优雅的解决方案)
@PostAuthorize("hasRole('ROLE_ADMIN') OR @securityCheck.check(returnObject, authentication)")
Page<Record> findByCycle_Id(@Param("id") Long id, Pageable pageable);
public boolean check(Page<Record> page, Authentication authentication) {
log.debug("===Security check for page===");
if (!page.hasContent()) {
return true;
}
long userId = page.getContent().get(0).getCycle().getUserId();
return Long.toString(userId).equals(authentication.getName());
}
最佳答案 如果我理解你的话……
首先,确保已启用SpEL EvaluationContext extension.
然后做这样的事情:
public interface RecordRepository extends JpaRepository<Record, Long> {
@Query("select r from Record r join r.cycle c where c.id = ?1 and (c.userId = ?#{@RecordRepository.toLong(principal)} or 1 = ?#{hasRole('ROLE_ADMIN') ? 1 : 0})")
Page<Record> findByCycleId(Long id, Pageable pageable);
default Long toLong(String name) {
return Long.valueOf(name);
}
}
我想主体包含userId的字符串表示,所以在这里我将它转换为long然后比较它们…
你也可以查看我的example与这个问题有关…
UPDATE
而不是SpEL表达式中的@ RecordRepository.toLong(主体)尝试使用T(java.lang.Long).valueOf(principal)并从repo中删除toLong方法.