java - Spring data rest findBy securityCheck 用于嵌套实体

标签 java spring-boot spring-data-rest

我正在为我的 REST 接口(interface)使用 Spring-data-rest,并且我已经在我公开的端点上实现了自定义安全检查。一切正常,但现在我遇到了一些不平凡的场景,我想知道 spring data rest 是否能够解决这个问题。

我有以下模型:

@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。

我已经像这样实现了 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);
    }
}

我想 principal 包含 userId 的字符串表示,所以在这里我将它转换为 long 然后比较它们......

你也可以查看我的example与此问题相关...

更新

在 SpEL 表达式中尝试使用 T(java.lang.Long).valueOf(principal) 而不是 @RecordRepository.toLong(principal) 并删除 toLong 来自你的 repo 的方法。

关于java - Spring data rest findBy securityCheck 用于嵌套实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47812031/

相关文章:

java - 为什么 Spring Boot 对实体的 "404 Not Found"处理方式不同?

Java spring 排序和过滤

Java 小程序与 Java7 和 8 的 list 属性存在问题

java - java中通过POST方法发送Xml字符串

java - 迭代器 vs for 循环以及为什么像 for 循环一样引入迭代器?

java - 让 Spring 在 rest 调用中接受 UTF-8 字符

java - 两个Maven Dependency 最新版本和旧版本冲突

java - Spring Boot 与 @PostConstruct 的集成测试取决于 @Before 部分

java - Spring Boot 返回 'HTTP/1.1 200' 而不是 'HTTP/1.1 200 OK'

java - Querydsl 绑定(bind) - 如何设置绑定(bind)以便参数可以与 Like 和 Contains 一起使用