繁体   English   中英

Spring Data Rest查找通过安全性检查嵌套实体

[英]Spring data rest findBy securityCheck for nested entity

我将Spring-data-rest用于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;

  ...
}

在获取周期时,我检查登录用户的ID是否与我的Cycle实体中的userId相同。

我已经实现了像这样的膀胱囊肿安全检查:

@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扩展

然后执行以下操作:

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);
    }
}

我想这个principal包含userId的字符串表示形式,因此在这里我将其转换为long形式然后进行比较...

您也可以检查我与此问题相关的示例 ...

更新

相反的@RecordRepository.toLong(principal)在规划环境地政司表达尝试用T(java.lang.Long).valueOf(principal) ,并删除toLong从您的回购方法。

如果您只需要在检查userId与您登录的用户相同的同时获取“周期”的特定记录,我将使用类似以下内容的方法:

Page<Record> findByCycle_IdAndUserId(Long cycleId, Long userId, Pageable pageable);

JPA本身可以处理很多工作,而无需您手动创建查询。 请参阅https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods中的查询方法。

当然,这意味着安全检查需要在控制器端通过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>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM