Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/spring-boot/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 通过securityCheck为嵌套实体查找Spring数据rest_Java_Spring Boot_Spring Data Rest - Fatal编程技术网

Java 通过securityCheck为嵌套实体查找Spring数据rest

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;

我将SpringDataREST用于我的rest接口,并且在我公开的端点上实现了自定义安全检查。一切正常,但现在我遇到了一些非常重要的场景,我想知道SpringDataREST是否能够解决这个问题

我有以下型号:

@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函数是一种“有弹性”的方式。