Java 通过securityCheck为嵌套实体查找Spring数据rest
我将SpringDataREST用于我的rest接口,并且在我公开的端点上实现了自定义安全检查。一切正常,但现在我遇到了一些非常重要的场景,我想知道SpringDataREST是否能够解决这个问题 我有以下型号:Java 通过securityCheck为嵌套实体查找Spring数据rest,java,spring-boot,spring-data-rest,Java,Spring Boot,Spring Data Rest,我将SpringDataREST用于我的rest接口,并且在我公开的端点上实现了自定义安全检查。一切正常,但现在我遇到了一些非常重要的场景,我想知道SpringDataREST是否能够解决这个问题 我有以下型号: @Entity public class Cycle { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "unique_cycle_id") private long id;
@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;
...
}
但现在,我正在尝试对记录实施类似的安全检查。因此,在获取给定周期的记录时,我需要检查周期的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访问周期内的用户id?如果不是,Spring实现此功能的正确方式是什么
对不起,我的问题不清楚。如果需要进一步解释,请告诉我
编辑:
通过访问post过滤器中返回的页面,我找到了快速而肮脏的解决方案。缺点是,当返回的数组为空时,我可以访问不属于登录用户的记录,因此我仍在寻找更优雅的解决方案
@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());
}
如果我理解正确的话 首先,确保已启用 然后像这样做:
@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());
}
}
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,然后比较它们
您也可以查看我与此问题相关的
更新
不要在SpEL表达式中使用@RecordRepository.toLongprincipal,而是尝试使用Tjava.lang.Long.valueOfprincipal,并从您的repo中删除toLong方法。如果您只需要在检查用户ID是否与您的登录用户相同时获取特定的周期记录,我只需要使用以下方法:
Page<Record> findByCycle_IdAndUserId(Long cycleId, Long userId, Pageable pageable);
JPA自己处理很多事情,而不需要您手动创建查询。请参阅上的查询方法
当然,这意味着安全检查需要在具有Spring security的控制器端处理,而不是在模型端。DAO不必关心请求是否有效/授权,因为这些检查是事先完成的
干杯您可以在应用程序中引入两个处理程序,如下所示:-
//This is your Request handler
public class CxfHttpRequestHandler extends AbstractPhaseInterceptor<Message> {
public CxfHttpRequestHandler() {
super("marshal");
}
@Override
public void handleMessage(final Message message) throws Fault {
//handle your all request here
}
}
//this is your Response handler
public class CxfHttpResponseHandler extends AbstractPhaseInterceptor<Message> {
public CxfHttpResponseHandler() {
super("pre-stream");
}
@Override
public void handleMessage(final Message message) throws Fault {
//handle your outgoing message here
}
}
Add the following in your spring-bean.xml file:-
<bean id="cxfHttpRequestHandler" class="com.yourpackage.CxfHttpRequestHandler" >
<description>
This Bean implements Interceptor for all request
</description>
</bean>
<bean id="cxfHttpResponseHandler" class="com.yourpackage.CxfHttpResponseHandler">
<description>
This Bean implements Interceptor for all response
</description>
</bean>
<cxf:bus>
<cxf:inInterceptors>
<ref bean="cxfHttpRequestHandler" />
</cxf:inInterceptors>
<cxf:outInterceptors>
<ref bean="cxfHttpResponseHandler" />
</cxf:outInterceptors>
</cxf:bus>
你的项目对我来说很有趣。它在github上吗?不幸的是,我没有这个问题的答案,但我很想在今天晚些时候看看。当我需要过多地定制SpringDataREST时,我总是放弃使用它,因为对我来说,它更像是一种负担,而不是一个支持性框架。也许你的项目可以改变我的想法,向我展示新的想法:不幸的是,这个项目不是开源的,但如果你想给我一个信息,我很乐意分享我的解决方案:我找到了一个解决我问题的肮脏的解决方案,但我仍然希望有一些更灵活的方式看到我的问题…谢谢你的回答。我一定会试试的。然而,我希望有一些解决方案,而不需要在代码中使用自定义查询和选择。正如您在Spring文档中看到的那样,这看起来不是很“有弹性”@Smajl-当问题涉及记录级安全性时,在查询中使用Spring Security SpEL函数是一种“有弹性”的方式。