Làm cách nào để kiểm tra quyền truy cập thực thể khi hiển thị trường xem?


8

Tôi có một thực thể tùy chỉnh. Có một cuộc gọi lại truy cập được xác định trong hook_entity_info()và nó được gọi khi tôi truy cập thực thể. Ngoài ra trong chế độ xem khi tôi chọn hiển thị các thực thể được hiển thị, thực thể chỉ được hiển thị khi người dùng được phép nhìn thấy thực thể.

Tuy nhiên, khi tôi thay đổi chế độ xem để hiển thị 'trường' thay vì 'thực thể được hiển thị', cuộc gọi lại truy cập sẽ không còn được gọi và người dùng có thể thấy tất cả các trường (và thuộc tính) của thực thể, bất kể mọi quyền. Nhìn vào truy vấn được thực hiện, điều này có ý nghĩa, các giá trị trường được nối vào và thực thể không bao giờ thực sự được tải.

Vậy, làm thế nào một người nên thực hiện quyền truy cập thực thể cho các khung nhìn khi hiển thị các trường (trong Drupal 7)?

Tôi đã tìm thấy Cách kiểm tra loại thực thể trong Chế độ xem khi sử dụng hook_field_access? , nhưng tôi giả sử rằng chỉ hoạt động cho các trường đã tham gia chứ không phải cho các thuộc tính thực thể cơ sở, vì vậy đó sẽ chỉ là một phần của giải pháp.


Bạn đã cân nhắc sử dụng view_mode tùy chỉnh chưa?
Darvanen

@Darvanen có, nhưng tôi cần hệ thống để được chứng minh. Vì vậy, tôi không thể giả sử mọi người sẽ sử dụng các thực thể được kết xuất.
Neograph734

@ Neograph734 Thực thể đó của bạn là một nút hay cái gì khác?
mchar

@mchar Đây là một thực thể tùy chỉnh được xây dựng với mô-đun Entity API.
Neograph734

Tôi nghĩ (chính xác nếu tôi sai) rằng giải pháp cho vấn đề của bạn là triển khai hook_node_granthook_node_access_records nhưng tôi không chắc liệu các hook này có áp dụng cho các thực thể tùy chỉnh hay không (ít nhất đây là cách hiệu quả nhất để kiểm soát truy cập theo như nó liên quan đến nodesDrupal.
mchar

Câu trả lời:


7

Giả sử mô-đun cung cấp thực thể của bạn đã thiết lập tích hợp Lượt xem và bạn không lo lắng về phân trang , bạn có thể gọi hook_views_pre_render()để lặp lại kết quả và gọi lại cuộc gọi lại truy cập của mình cho từng thực thể trong bảng cơ sở của bạn và lọc ra các mục mà người dùng không có quyền truy cập vào:

/**
 * Implements hook_views_pre_render().
 */
function MYMODULE_views_pre_render(&$view) {
  global $user;

  // Iterate over View results for our custom entity
  if ($view->base_table == 'my_entity_base_table') {
    foreach ($view->result as $index => $row) {

      // Presuming eid is the entity PK
      $results = entity_load('my_entity_machine_name', array($row->eid));
      if (!empty($results)) {
        $entity = $results[$row->eid];

        // If the custom access callback returns FALSE, remove from results.
        if (!MYMODULE_my_entity_access_callback('view', $entity, $user)) {
          unset($view->result[$index]);
        }
      }
    }
  }
}

Nếu phân trang là một mối quan tâm , đó là một vấn đề khó khăn hơn; điều chỉnh kết quả ngắt kết quả bù nhất quán (ví dụ: trang 1 có thể trả về 4 kết quả, trang 2 có thể trả về 10 kết quả). Thêm vào đó, kết quả của truy vấn SQL không thể điều chỉnh thông tin chỉ được biết bằng cách thực thi PHP.

Trong các trường hợp đó, bạn sẽ phải điều chỉnh phương thức của mình (ví dụ: hook_views_query_alter()nếu cuộc gọi lại truy cập dựa trên truy vấn DB, thay đổi tùy chọn xem máy nhắn tin, v.v.) để phù hợp với chế độ gọi lại truy cập thao tác chế độ xem.


1
Mặc dù đây chắc chắn là một sự khởi đầu, nó phá vỡ số lượt xem (không phải 25 mục trên mỗi trang nhưng ít hơn, đôi khi là 0). Có cách nào để xử lý việc này trước khi tính toán phân trang không?
Neograph734

1
Có vẻ như phân trang đã có trong truy vấn: ... LIMIT 25 OFFSET 0vì vậy cách duy nhất để duy trì hoạt động phân trang là hành động trước khi truy vấn được hoàn thành. Nhưng tôi không thể nhúng cuộc gọi lại truy cập của mình trong truy vấn. Vì vậy, nó không thể được thực hiện?
Neograph734

1
Tôi thậm chí không nghĩ về nó vì nó không được đề cập. Dù sao, đối tượng khung nhìn chứa thuộc $querytính mà thuộc tính máy nhắn tin có thể được thao tác để phản ánh số lượng đã thay đổi.
Shawn Conn

1
Tôi cũng không Shawn, nhưng tôi đã gặp phải nó khi thực hiện giải pháp của bạn. Điều này chưa thực sự hiệu quả (bạn đặt tổng số lượng mục thành số lượng truy vấn được trả về, vì vậy nó sẽ không bao giờ lớn hơn số lượng mục trên mỗi trang (25)). Tôi sẽ thử điều này với một truy vấn đếm riêng để có được tổng số lượng vật phẩm.
Neograph734

1
Xin lỗi, đó là một chỉnh sửa vội vàng khi tôi bị khủng hoảng thời gian. Tôi nghĩ rằng trước đây tôi đã giải quyết vấn đề chính xác này, nhưng khi xem lại mã đó, đó là trường hợp chúng ta có thể có được bằng cách phân trang mờ. Tôi cập nhật câu trả lời cho phù hợp.
Shawn Conn

1

Cuối cùng, tôi đã tìm được một phương thức hoạt động theo cách tương tự như các khung nhìn với các nút.

Trong hook_views_data()(hoặc hook_views_data_alter()), đảm bảo thêmaccess query tag phím bảng. Bạn có thể thấy Views thực hiện điều này cho các nút cũng như trong node_views_data().

$data['example_table']['table']['base'] = array(
  'field' => 'nid', // This is the identifier field for the view.
  'title' => t('Example table'),
  'help' => t('Example table contains example content and can be related to nodes.'),
  'weight' => -10,

  'access query tag' => 'my_entity_access' // <- Add this.
);

Sau đó thêm việc thực hiện của riêng bạn hook_query_TAG_alter . Điều này sẽ thay đổi mọi truy vấn nơi thẻ này được thêm vào. Do sự thay đổi ở trên của chúng tôi, điều này sẽ được tự động áp dụng cho tất cả các danh sách dữ liệu Lượt xem, nhưng thẻ cũng có thể được thêm thủ công .

Có một số thủ thuật tuyệt vời _node_query_node_access_alter()được gọi từ node_query_node_access_alter () (triển khai mô-đun nút của hook_queryiah_alter).

function mymodule_query_my_entity_access_alter(QueryAlterableInterface $query) {
  global $user;

  // Read meta-data from query, if provided.
  if (!$account = $query->getMetaData('account')) {
    $account = $user;
  }
  if (!$op = $query->getMetaData('op')) {
    $op = 'view';
  }

  // From here every query will be different depending on your own needs.
  // Since my entity has a privacy parameter that is either public or private,
  // I chose to implement this as follows:

  // Prepare a database OR.
  $or = db_or();

  // If the user has public view permissions, add it to the OR.
  if (user_access('view public my_entities', $account)) {
    $or->condition('example_table.privacy', 'public');
  }

  // If the user has non-public view permissions, add it to the OR.
  if (user_access('view private my_entities', $account)) {
    $or->condition('example_table.privacy', 'public', '<>');
  }

  // Add the compiled set of rules to the query. 
  $query->condition($or);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.