Spring findBy securityCheck data lookup for nested object

I am using Spring -data-rest for my REST interface and I have implemented custom security checks on my open endpoints. Everything works fine, but now I came across some non-trivial scenario, and I wonder if this spring resource will be able to solve this issue.

I have the following model:

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

  ...
}

When retrieving the loop, I verify that the logged in user has the same identifier as userIdin my loop object.

I implemented cystom security check as follows:

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

But now I am trying to perform a similar security check for records. Therefore, when retrieving records for a given loop, I need to verify that the userId loop matches the identifier in the authentication object.

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

userId , securityCheck? , spring ?

, . , .

EDIT: , . , , , ( )

@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());
  }
+4
3

...

-, , Spene 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, ...

, ...

UPDATE

@RecordRepository.toLong(principal) SpEL T(java.lang.Long).valueOf(principal) toLong .

+1

"", , 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 . DAO , /, .

0

You can enter two handlers in your application as shown below: -

  //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>
0
source

Source: https://habr.com/ru/post/1690777/


All Articles